18

I'm looking to get a list of just file names (without the rest of the path) when executing the find command from a terminal. How do I accomplish this on the mac?

0

7 Answers 7

24

With basename:

find . -type f -exec basename {} \;

4
  • What are curly braces for? Commented Jul 17, 2013 at 12:51
  • basename is run once for every found file, denoted by {}. Commented Jul 17, 2013 at 14:02
  • what is the mean of the \ and ; ? Commented Dec 24, 2016 at 10:49
  • @neouyghur ; terminates the -exec action. The \ is needed because ; also has special meaning to the shell. Commented Sep 22, 2017 at 20:49
7

Evilsoup mentioned that what was posted doesn't work for spaced file names. So instead you could use:

find . -type f -print0 | while IFS= read -r -d '' filename; do echo ${filename##*/}; done 
2
  • This will break on files with spaces in their names (see parsing ls on greg's wiki) Commented Jul 16, 2013 at 22:08
  • +1 for speed. I don't know if I did something wrong, but this one took 1 second on my $HOME, whereas all others took around 10 seconds. Of course, I would need more than 10 seconds to look this up and type it. Commented Jul 16, 2013 at 23:19
2

With GNU find, you can do:

 find ~/tmp/ -printf "%f\n" 

This is probably worth trying in OS X too.

3
  • 3
    -printf isn't supported on OS X's BSD find. Commented Jul 16, 2013 at 21:22
  • 1
    Also, -printf bears little relation to the C printf or the POSIX shell utility printf. Using this historic function name for something different is very poorly considered. The conservative BSD guys likely see it the same way, so we won't probably won't see clone of -printf in the BSD find, under that name. Commented Jul 17, 2013 at 0:42
  • I disagree that it's poorly considered to use a familiar function name to perform a similar task in a different context. Why BSD will probably never support it is another matter. Commented Jul 17, 2013 at 14:02
2

There is a better way to strip everything but the last portion of a file path; with awk. It is better because awk is not executed once for every file. In some cases this matters.

find ~/tmp/ -type f | awk -F/ '{ print $NF }' 

We look only for files in ~/tmp and we get a list where every entry is separated by slashes. Hence, we use a slash as the field separator (-F/) and print the field parameter ($1..$9) that corresponds to the last field ($NF).

2
  • This is the fastest I tested. Commented Jul 17, 2013 at 14:25
  • I've been using Cygwin lately, and creating a process in windows is super expensive... Commented Jul 17, 2013 at 14:30
2

EDIT:

Using sed:

$ find . -type f | sed 's/.*\///' 

Using the xargs command, as mentioned in the response of @nerdwaller

$ find . -type f -print0 | xargs --null -n1 basename 
3
  • 1
    Thanks for pointing that one out, +1, I haven't used xargs much... Definitely should since you dropped quite a few characters off my command. Commented Jul 16, 2013 at 20:49
  • This one breaks when files have spaces. It works like this, at least in a quick test: find . -type f -print0| xargs --null -n1 basename Commented Jul 17, 2013 at 14:28
  • Neither of --null or -n1 options is available on OSX Commented Mar 23, 2018 at 16:58
1

You can call sh from within find's -exec option and avoid using uneccesary pipes. This also has the advantage that you don't need to worry about funny filenames (spaces, newlines, etc.):

find . -type f -exec sh -c 'echo "${0##*/}"' {} \; 
1

What about this:

find … | egrep -o -e '[^/]+$' 

Advantage: Only exactly one additional process is spawned, not one for each result.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.