Bash – Using bash variable substitution instead of cut/awk

awkbashcut

Can I use bash variable substitution to extract a piece of a variable based on a delimeter? I'm trying to get the immediate directory name of a filename (in this case, foo).

$ filename=./foo/bar/baz.xml

I know I could do something like

echo $filename | cut -d '/' -f 2

or

echo $filename | awk -F '/' '{print $2}'

but it's getting slow to fork awk/cut for multiple filenames.

I did a little profiling of the various solutions, using my real files:

echo | cut:

real    2m56.805s
user    0m37.009s
sys     1m26.067s

echo | awk:

real    2m56.282s
user    0m38.157s
sys     1m31.016s

@steeldriver's variable substitution/shell parameter expansion:

real    0m0.660s
user    0m0.421s
sys     0m0.235s

@jai_s's IFS-wrangling:

real    1m26.243s
user    0m13.751s
sys     0m28.969s

Both suggestions were a huge improvement over my existing ideas, but the variable substitution is fastest because it doesn't require forking any new processes.

Best Answer

You can remove the shortest leading substring that matches */

tmp="${filename#*/}"

and then remove the longest trailing substring that matches /*

echo "${tmp%%/*}"
Related Question