Bash substitution giving basename with one leading directory component

For GNU Screen titling purposes, I'd like to get ahold of the current directory name prefixed by the name of its parent. For example, within directories

/home/rhys/share/pkgconfig
/home/rhys
/home
/

producing outputs

share/pkgconfig
home/rhys
home
/

In Bash, starting from a guess like

echo $(basename $(dirname $PWD))/$(basename $PWD)

one can arrive at a better solution

echo $(basename "${PWD%/*}")/${PWD##*/}

where I say better because two fewer processes are spawned.

Anyone have a cute trick to avoid using basename at all? This is for something run every shell prompt so it'd be nice to be as lightweight as possible.

Answers


for p in /home/rhys/share/pkgconfig /home/rhys /home /; do
  [[ $p =~ .*/([^/]+/[^/]+)$ ]] && echo "${BASH_REMATCH[1]}" || echo "$p"
done

As a function:

last2() { [[ $1 =~ .*/([^/]+/[^/]+)$ ]] && echo "${BASH_REMATCH[1]}" || echo "$1"; }

Should work on bash >= 3.2


How about this, using bash and awk:

awk -F'/' '{print $(NF-1)"/"$NF}' <<<"$PWD"
Edit

The previous one is not quite right, as it prints /home rather than just home. Maybe you can live with that. If not, this one works fully:

awk -F'/' '{if (NF==2 && $2) {$0=$2} else {$0=$(NF-1)"/"$NF}}1' <<<"$PWD"

Testing it out:

awk -F'/' '{if (NF==2 && $2) {$0=$2} else {$0=$(NF-1)"/"$NF}}1' <<EOF
/home/rhys/share/pkgconfig
/home/rhys
/home
/
EOF

Output:

share/pkgconfig
home/rhys
home
/

Here's a function that will work in bash 4 or later:

trim () (
  IFS=/
  read -a c <<< "$1"
  unset c[0]
  fragment="${c[*]: -2:2}"
  echo "${fragment:-/}"
)

for p in /home/rhys/share/pkgconfig /home/rhys /home /; do
  trim "$p"
done

share/pkgconfig
home/rhys
home
/

Need Your Help

How to implement outofbound on switch-case

java android arrays string web-services

I have the next error: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 I hope somebody can help me to resolve this. I think I need to check for String not to be null, but I don't know how to