Get last field using awk substr
Matthew Martinez
I am trying to use awk to get the name of a file given the absolute path to the file.
For example, when given the input path /home/parent/child/filename I would like to get filename
I have tried:
awk -F "/" '{print $5}' inputwhich works perfectly.
However, I am hard coding $5 which would be incorrect if my input has the following structure:
/home/parent/child1/child2/filenameSo a generic solution requires always taking the last field (which will be the filename).
Is there a simple way to do this with the awk substr function?
19 Answers
Use the fact that awk splits the lines in fields based on a field separator, that you can define. Hence, defining the field separator to / you can say:
awk -F "/" '{print $NF}' inputas NF refers to the number of fields of the current record, printing $NF means printing the last one.
So given a file like this:
/home/parent/child1/child2/child3/filename
/home/parent/child1/child2/filename
/home/parent/child1/filenameThis would be the output:
$ awk -F"/" '{print $NF}' file
filename
filename
filename 3 In this case it is better to use basename instead of awk:
$ basename /home/parent/child1/child2/filename filename 1 If you're open to a Perl solution, here one similar to fedorqui's awk solution:
perl -F/ -lane 'print $F[-1]' input-F/ specifies / as the field separator$F[-1] is the last element in the @F autosplit array
Another option is to use bash parameter substitution.
$ foo="/home/parent/child/filename"
$ echo ${foo##*/}
filename
$ foo="/home/parent/child/child2/filename"
$ echo ${foo##*/}
filename It should be a comment to the basename answer but I haven't enough point.
If you do not use double quotes, basename will not work with path where there is space character:
$ basename /home/foo/bar foo/bar.png
barok with quotes " "
$ basename "/home/foo/bar foo/bar.png"
bar.pngfile example
$ cat a
/home/parent/child 1/child 2/child 3/filename1
/home/parent/child 1/child2/filename2
/home/parent/child1/filename3
$ while read b ; do basename "$b" ; done < a
filename1
filename2
filename3 0 I know I'm like 3 years late on this but.... you should consider parameter expansion, it's built-in and faster.
if your input is in a var, let's say, $var1, just do ${var1##*/}. Look below
$ var1='/home/parent/child1/filename'
$ echo ${var1##*/}
filename
$ var1='/home/parent/child1/child2/filename'
$ echo ${var1##*/}
filename
$ var1='/home/parent/child1/child2/child3/filename'
$ echo ${var1##*/}
filename Like 5 years late, I know, thanks for all the proposals, I used to do this the following way:
$ echo /home/parent/child1/child2/filename | rev | cut -d '/' -f1 | rev
filenameGlad to notice there are better manners
you can skip all of that complex regex :
echo '/home/parent/child1/child2/filename' | mawk '$!_=$-_=$NF' FS='[/]' filename2nd to last :
mawk '$!--NF=$NF' FS='/' child23rd last field :
echo '/home/parent/child1/child2/filename' | mawk '$!--NF=$--NF' FS='[/]' child14th-last :
mawk '$!--NF=$(--NF-!-FS)' FS='/' echo '/home/parent/child000/child00/child0/child1/child2/filename' | child0 echo '/home/parent/child1/child2/filename' parentmajor caveat :
- `gawk/nawk` has a slight discrepancy with `mawk` regarding - how it tracks multiple, - and potentially conflicting, decrements to `NF`, - so other than the 1st solution regarding last field, - the rest for now, are only applicable to `mawk-1/2` You can also use:
sed -n 's/.*\/\([^\/]\{1,\}\)$/\1/p'or
sed -n 's/.*\/\([^\/]*\)$/\1/p' 1