56

I'd like to use find to list all files and directories recursively in a given root for a cpio operation. However, I don't want the root directory itself to appear in the paths. For example, I currently get:

$ find diskimg
diskimg
diskimg/file1
diskimg/dir1
diskimg/dir1/file2

But, I'd like to get

file1
dir1
dir1/file2

(note the root is also not in my desired output, but that's easy to get rid of with tail).

I'm on OS X, and I'd prefer not to install any extra tools (e.g. GNU find) if possible, since I'd like to share the script I'm writing with other OS X users.

I'm aware this can be done with cut to cut the root listing off, but that seems like a suboptimal solution. Is there a better solution available?

nneonneo
  • 1,088

4 Answers4

48

cd into the directory first:

cd diskimg && find . 

On completion, you will be back in your root directory.

Your files will be prepended with ./ in this case; the only way I see around that would be using cut:

{ cd diskimg && find .; } | tail -n +2 | cut -c 3-

Use a subshell to avoid changing your shell's current directory (this isn't necessary if you're piping the output as the left-hand side of a pipe already runs in a subshell).

(cd diskimg && find .)
Stephan
  • 2,911
  • 11
    to be back in the original dir on completion: add parenthesis: (cd diskimg && find . ; ) . That way the cd diskimg && find . is done in a subshell : when that subshell exits you are back to your own shell, in whatever directory you were. – Olivier Dulac Dec 12 '13 at 09:45
  • 5
    find * is another way around the useless prefix – nik.shornikov Jan 02 '17 at 16:45
44

Another, more complex but only using find approach from my other answer:

find diskimg -mindepth 1 -printf '%P\n'
Stephan
  • 2,911
33

Use the realpath utility:

find diskimg -exec realpath --relative-to diskimg {} \;
peterph
  • 30,838
dwjbosman
  • 469
24

If what you are trying to do is not too complex, you could accomplish this with sed:

find diskimg | sed -n 's|^diskimg/||p'

Or cut:

find diskimg | cut -sd / -f 2-
BriGuy
  • 3,211
  • 1
  • 15
  • 20
  • you can choose (almost) any separator for the command, so: find diskimg | grep -v '^diskimg$' | sed -e 's|^diskimg/||' (note I added also '-e', and a ^ as good practice (not necessary here, as you are sure every lines will have this... but still good practice, and saves some cpu ;)) – Olivier Dulac Dec 12 '13 at 09:38
  • another way without grep: find diskimg | sed -e 's|^diskimg/*||' (the '/*' will match any number of '/', even 0) – Olivier Dulac Dec 12 '13 at 09:48
  • This cut command is cleaner than the one I used; I like it. (The sed solution is nice too, but the repetition of diskimg/ is a little unfortunate). – nneonneo Dec 12 '13 at 20:12
  • cut -c9- should be faster. the prefix is constant – milahu Mar 15 '22 at 16:13