6

I need to print a list of "full" relative paths of all the files present in a directory and in its sub-directories. I used to do this with du and grep:

du -a <path_to_directory> | grep -Po '[0-9]+\t\/\K.*'

But du replaces part of the paths with dots if they are too long.

Which is a good alternative?

Parsing ls is not an option.

11

The most straightforward option would be find:

$ cd /usr/lib; find .
.
./libxcb-icccm.so.4.0.0
./libbz2.so.1.0.6
./libdca.so.0
./libxcb-composite.so
./libyajl.so
./libswscale.so
./libxvidcore.so.4.3
./libjasper.so.1
./libdrm_intel.so.1
...

It has various tests for filtering such as:

  • -type to filter based on type (regular file f, directory d, etc.)
  • -mindepth and -maxdepth to set the depths to which find should search (not really tests as such)
  • -name and -path to filter based on filename and path, supporting wildcards.
  • and a lot of other tests, for permissions, ownership, times, etc.

It offers a variety of output formats, using the -printf option.


Depending on the shell and the options enabled, you can also use globbing for this purpose. For example, in bash:

$ shopt -s globstar; printf "%s\n" **
accountsservice
accountsservice/accounts-daemon
aisleriot
aisleriot/ar-cards-renderer
aisleriot/guile
aisleriot/guile/2.0
aisleriot/guile/2.0/accordion.go
aisleriot/guile/2.0/agnes.go
aisleriot/guile/2.0/aisleriot
aisleriot/guile/2.0/aisleriot/api.go
...

And in zsh:

$ printf "%s\n" **/*
accountsservice
accountsservice/accounts-daemon
aisleriot
aisleriot/ar-cards-renderer
aisleriot/guile
aisleriot/guile/2.0
aisleriot/guile/2.0/accordion.go
aisleriot/guile/2.0/agnes.go
aisleriot/guile/2.0/aisleriot
aisleriot/guile/2.0/aisleriot/api.go
...
  • 1
    find /some/absolute/path -type f -printf '%P\n' comes to mind – steeldriver Mar 24 '15 at 22:55
  • Nice, I could even finally get rid of directories. find . -type f | sed -r 's/^\///g' and find . -type f | sed -r 's/^\.\///g' did the trick. Thanks – kos Mar 24 '15 at 23:09
  • @kos If you want to remove the ./ check out steeldriver's suggestion instead of using sed - it's not recommended for the same reason parsing ls isn't. If you must use sed, use -print0 and sed -z. – muru Mar 24 '15 at 23:12
  • @muru Isn't ^\. or ^\.\/ specific enough by the way? – kos Mar 24 '15 at 23:28
  • @muru Actually I still have dots in the middle of some path, which I missed at first. So find is not an option. And I'm unable to run shopt inside a bash script, which probably is the expected behavior – kos Mar 25 '15 at 1:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.