73

I would like to create symbolic links (ln -s) to all files (or a class of files, e.g. ending with .bar) in a certain directory. Say I'm in the cwd and type ls ../source/*.bar gives me

foo.bar
baz.bar

how can I pass the parameter list to ln -s that it finally resolves to

ln -s ../source/foo.bar
ln -s ../source/baz.bar

Of course I know I can write a bash script, but there should be something simpler involving xargs or so since it seems to be a common task - at least for me.

dastrobu
  • 833
  • 1
  • 6
  • 6

4 Answers4

121

ln does take multiple arguments, but don't forget to give a target directory in that case.

So, in your example . is the target directory, so it should be as easy as

ln -s ../source/*.bar .

From man ln; the command above uses the 3rd form:

ln [OPTION]... [-T] TARGET LINK_NAME   (1st form)
ln [OPTION]... TARGET                  (2nd form)
ln [OPTION]... TARGET... DIRECTORY     (3rd form)
ln [OPTION]... -t DIRECTORY TARGET...  (4th form)
  • In the 1st form, create a link to TARGET with the name LINK_NAME.
  • In the 2nd form, create a link to TARGET in the current directory.
  • In the 3rd and 4th forms, create links to each TARGET in DIRECTORY.
mpy
  • 27,002
  • 7
  • 85
  • 97
  • 3
    This doesn't work if there are no files `*.bar`. It will create a link with the name `"*.bar"`, which is not what you want. – Nimrod May 09 '17 at 16:28
  • 1
    @Nimrod: That's true, but you can tell _bash_ that you want it to report an error instead via `shopt -s failglob`; see e.g. https://unix.stackexchange.com/a/216227/33390 (The equivalent in _zsh_ is `setopt nomatch`, which is turned on by default) – mpy May 09 '17 at 17:25
  • For the failure reporting, what's the equivalent for csh or generically sh for any shell? – David May 05 '23 at 20:18
10

You can try recursively either with using globstar (bash/zsh set by: shopt -s globstar):

ls -vs ../**/*.bar .

Note: Added -v for verbose.

Or if the list is too long, using find utility:

find .. -name \*.bar -exec ln -vs "{}" dest/ ';'

This will create links in dest/, or change it to . for current folder.

kenorb
  • 24,736
  • 27
  • 129
  • 199
6

Use find

certainDir="/path/to/dir"
find -name "*.bar" -exec ln -s {} "$certainDir" \;

Also, remember to use full paths (where possible) with symlinks.

slhck
  • 223,558
  • 70
  • 607
  • 592
justbrowsing
  • 2,659
  • 16
  • 16
  • 2
    Thanks, but isn't it `find $certainDir -name "*.bar" -exec ln -s {} \;`? And why should I use full paths? I find it quite convenient to know that links stay intact when I move a directory tree around wihch has some internal links. – dastrobu Aug 19 '13 at 08:56
  • That depends where you want to symlink the directories. And I can't remember why full paths are a good idea, it might have been for hard links but I burned that into my mind for a reason. Hmmm. – justbrowsing Aug 19 '13 at 08:59
  • Thanks, your answer is great. Since mpy's answer is the simpler solution to the question, the point goes to him/her. I would accept both answers, if I could. – dastrobu Aug 19 '13 at 09:07
5

cp with -s option can create a soft links (or -l for hard links).

From current directory can by used like this:

$ cp -s ../path/with/scripts/* .

In your case it will be like this:

$ cp -s ../source/*.bar .
Dmitry
  • 204
  • 3
  • 6
  • 1
    Found an interesting related post on symlinks with cp: https://unix.stackexchange.com/questions/46047/create-symbolic-links-with-wildcards – David May 05 '23 at 20:25