I'm trying to use find to create a bunch of symlinks but using the result with {} includes ./ before each filename. How can I avoid that?

find . -type l -name '*.h' -exec ln -s /sourcedir/{} /destinationdir/{} \;
  • Is your find supporting the -printf option?
    – manatwork
    Apr 12 '13 at 11:35
  • yes i think it does Apr 12 '13 at 11:38
  • See the find . -type l -name '*.h' -printf 'ln -s /sourcedir/%f /destinationdir/%f\n''s output. If you like it, pipe it to sh. Of course, special characters in the file names will be a problem.
    – manatwork
    Apr 12 '13 at 11:41
  • @manatwork I think you have the best answer there. If you post it as an answer I'll mark it as accepted Apr 12 '13 at 11:56
  • 1
    If all the relevant files (type l, name *.h) reside under /sourcedir/ then use find sourcedir -type l -name '*.h' -exec ln -s {} /destinationdir/{} \; ... You would run the find command from the parent of /sourcedir, which is the root. On second thought that won't work because it will try to create a link called /destinationdir/sourcedir/file.h
    – Johan
    Apr 17 '13 at 9:55

You only have to change one character in your command:

find * -type l -name '*.h' -exec ln -s /sourcedir/{} /destinationdir/{} \;
#    ^
  • 1
    Good point, but it should be noted though that it would fail if any file is named !, ( or ) or anything starting with a - in the current directory. It will also skip the hidden files and dirs in the current directory. Apr 12 '13 at 13:07
  • @StephaneChazelas You are right. I had thought about the hidden files and dirs myself but found only one such file in the 75K .h on my systems (ubuntu Linux).
    – Anthon
    Apr 12 '13 at 13:17
  • If I find stuff in another directory (eg. find src/ -type l), is there a way to exclude src/ from the results? Apr 22 at 11:38
  • I don't understand why you would not do cd src; find * -type l in that case.
    – Anthon
    Apr 22 at 17:08

Use the standard syntax, like:

S=/sourcedir D=/destdir find . -type l -name '*.h' -exec sh -c '
  for i do
    ln -s -- "$S${i#.}" "$D/$i"
  done' sh {} +

If you want to use GNUisms, you could do:

find . -type l -name '*.h' -printf '/sourcedir/%P\0/destdir/%P\0' |
  xargs -r0n2 ln -s

Or if /sourcedir is the current directory:

find "$PWD" -type l -name '*.h' -printf '%p\0/destdir/%P\0' |
  xargs -r0n2 ln -s

find will print names relative to the paths you provide as arguments. In this case, the path is ., so all the names will begin with ./. To get absolute paths, you need to provide an absolute path as input:

find "$PWD" -type l -name '*.h'

This command uses the $PWD environment variable, which contains the absolute path of the current working directory, so it should preserve the meaning of your original command.

  • 3
    He would then need to strip that $PWD off the destination of the ln command. Apr 12 '13 at 11:44
  • good point. Also I think I was answering a question he didn't ask. :( Apr 12 '13 at 11:45
find . -type l -name '*.h' -print0 | cut -z -c3- \
    | xargs -0 -I '{}' ln -s '/sourcedir/{}' '/destinationdir/{}'

man find

  • -print0 print the full file name on the standard output, followed by a null character.

man cut - remove sections from each line of files

  • -z line delimiter is NUL, not newline.
  • -c select only these characters.
  • N- from N'th byte, character or field, counted from 1, to end of line.

man xargs - build and execute command lines from standard input.

  • xargs [options] [command [initial-arguments]]
  • -0 Input items are terminated by a null character instead of by whitespace, and the quotes and backslash are not special (every character is taken literally).
  • -I replace-str Replace occurrences of replace-str in the initial-arguments with names read from standard input. Also, unquoted blanks do not terminate input items; instead the separator is the newline character. Implies -L 1.
  • -L max-lines Use at most max-lines nonblank input lines per command line.

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.