views:

233

answers:

8

I have a list of file locations in a text file. For example:

/var/lib/mlocate

/var/lib/dpkg/info/mlocate.conffiles

/var/lib/dpkg/info/mlocate.list

/var/lib/dpkg/info/mlocate.md5sums

/var/lib/dpkg/info/mlocate.postinst

/var/lib/dpkg/info/mlocate.postrm

/var/lib/dpkg/info/mlocate.prerm

What I want to do is use sed or awk to read from the end of each line until the first forward slash (i.e., pick the actual file name from each file address).

I'm a bit shakey on syntax for both sed and awk. Can anyone help?

+4  A: 

Use command basename

$~hawk] basename /var/lib/mlocate
mlocate
Neeraj
Thanks alot, so simple
paultop6
basename is good for one file at a time; to process the names in a file, sed or awk works as well if not better.
Jonathan Leffler
+1  A: 

There's really no need to use sed or awk here, simply us basename

IFS=$'\n'
for file in $(cat filelist); do
   basename $file;
done

If you want the directory part instead use dirname.

honk
Won't work if filenames contain spaces.
Dennis Williamson
@dennis who has spaces in filenames anyway??? ;) fixed
honk
a lot a out there has spaces in file names
ghostdog74
no need to call external command basename.
ghostdog74
@ghost I added the `IFS` line. That changes the character that separates entries in that list I iterate over from space to `\n`.
honk
+1 for $'...' syntax. I'd never encountered that (after all these years of bashing)
Adrian Pronk
+4  A: 
$ sed -e 's!^.*/!!' locations.txt
mlocate
mlocate.conffiles
mlocate.list
mlocate.md5sums
mlocate.postinst
mlocate.postrm
mlocate.prerm

Regular-expression quantifiers are greedy, which means .* matches as much of the input as possible. Read a pattern of the form .*X as "the last X in the string." In this case, we're deleting everything up through the final / in each line.

I used bangs rather than the usual forward-slash delimiters to avoid a need for escaping the literal forward slash we want to match. Otherwise, an equivalent albeit less readable command is

$ sed -e 's/^.*\///' locations.txt
Greg Bacon
+3  A: 

I am for "basename" too, but for the sake of completeness, here is an awk one-liner:

awk -F/ 'NF>0{print $NF}' <file.txt
marco
for completeness get rid of the empty lines too `{if(NF>0) print $NF}` ;) +1
honk
you are right, I have edited my code ;)
marco
+1  A: 

Pure Bash:

while read -r line
do
    [[ ${#line} != 0 ]] && echo "${line##*/}"
done < files.txt

Edit: Excludes blank lines.

Dennis Williamson
Cool. Any chance to squeeze a test for empty `line` into the `{}`?
honk
A: 

@OP, you can use awk

awk -F"/" 'NF{ print $NF }' file 

NF mean number of fields, $NF means get the value of last field

or with the shell

while read -r line
do
    line=${line##*/} # means longest match from the front till the "/" 
    [ ! -z  "$line" ] && echo $line
done <"file"

NB: if you have big files, use awk.

ghostdog74
A: 

Thius would do the trick too if file contains the list of paths

 $ xargs -d '\n' -n 1 -a file basename
dtmilano
this will break on files with spaces
ghostdog74
-d '\n' prevents breaking the line on whitespaces
dtmilano
A: 

This is a less-clever, plodding version of gbacon's:

sed -e 's/^.*\/\([^\/]*\)$/\1/'
13ren