Home > front end >  Parse filename string and extract parent at specific level using shell
Parse filename string and extract parent at specific level using shell

Time:04-12

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.

  • Related