I'd like to get the name of the immediate parent directory of a given file, e.g. foo
given /home/blah/foo/bar.txt
, using a parameter expansion. Right now I can do it in two lines:
f="/home/blah/foo/bar.txt"
dir_name="${f%/*}"
immediate_parent="${dir_name##*/}"
But I'm very new to parameter expansions, so I assume this could be optimized. Is there a way to do it in only one line?
You can't do it with a single parameter expansion, but you can use =~
, Bash's regex-matching operator:
[[ $f =~ ^.*/(.+)/.+$ ]] && immediate_parent=${BASH_REMATCH[1]}
Note: Assumes an absolute path with at least 2 components.
If calling an external utility is acceptable, awk
offers a potentially simpler alternative:
immediate_parent=$(awk -F/ '{ print $(NF-1) }' <<<"$f")
As for why it can't be done with a single parameter expansion:
Parameter expansion allows for stripping either a prefix (#
/ ##
) or a suffix (%
/ %%
) from a variable value, but not both.
Using a single parameter expansion, extracting an inner substring can only be done by character position and length; e.g., a hard-coded solution based on the sample input would be: immediate_parent=${f:11:3}
You can use arithmetic expressions and even command substitutions as parameter expansion arguments, but the pointlessness of this approach - at least in this scenario - becomes obvious if we try it; note the embedded command substitutions - the first to calculate the character position, the second to calculate the length:
immediate_parent=${f:$(d=${f%/*/*}; printf %s ${#d})+1:$(awk -F/ '{ print length($(NF-1)) }' <<<"$f")}