I have a filename as a string, say filname="a/b/c/d.png"
.
Is there a general method to extract the parent directory at a given level using ONLY shell parameter expansion?
I.e. I would like to extract "level 1" and return c
or "level 2" and return b
.
Explicitly, I DO NOT want to get the entire parent path (i.e. a/b/c/
, which is the result of ${filename%/*}
).
CodePudding user response:
Using just shell parameter expansion, assuming bash, you can first transform the path into an array (splitting on /
) and then ask for specific array indexes:
filename=a/b/c/d.png
IFS=/
filename_array=( $filename )
unset IFS
echo "0 = ${filename_array[0]}"
echo "1 = ${filename_array[1]}"
echo "2 = ${filename_array[2]}"
echo "3 = ${filename_array[3]}"
Running the above produces:
0 = a
1 = b
2 = c
3 = d.png
These indexes are the reverse of what you want, but a little arithmetic should fix that.
CodePudding user response:
Using zsh
, the :h
modifier trims the final component off a path in variable expansion.
The (s:...:)
parameter expansion flag can be used to split the contents of a variable. Combine those with normal array indexing where a negative index goes from the end of the array, and...
$ filename=a/b/c/d.png
$ print $filename:h
a/b/c
$ level=1
$ print ${${(s:/:)filename:h}[-level]}
c
$ level=2
$ print ${${(s:/:)filename:h}[-level]}
b
You could also use array subscript flags instead to avoid the nested expansion:
$ level=1
$ print ${filename[(ws:/:)-level-1]}
c
$ level=2
$ print ${filename[(ws:/:)-level-1]}
b
w
makes the index of a scalar split on words instead of by character, and s:...:
has the same meaning, to say what to split on. Have to subtract one from the level to skip over the trailing d.png
, since it's not stripped off already like the first way.