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.
- Nesting prefix- and suffix-trimming expansions, while supported in principle, does not help, because you'd need iterative modification of values, whereas an expansion only ever returns the modified string; in other words: the effective overall expansion still only performs a single expansion operation, and you're again stuck with either a prefix or a suffix operation.
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")}