I want to create symlinks to multiple files:

ln -s dev-*.php 's/dev-(.*\.php)/$1/'

Results hoped for:  
    site.php links to dev-site.php  
    file.php links to dev-file.php

What's the most concise way to achieve this?


Well, if it's all in the same directory you could do something like this in bash or any other Bourne-style/POSIX shell:

for FILE in dev-*; do ln -s "$FILE" "${FILE#dev-}"; done

which would create symlinks without "dev-" to files beginning with "dev-".

  • Looks like the code formatter doesn't like the ${param#word} format. In this context the # is not treated as a comment but as an instruction to remove dev- from the value stored in FILE Feb 11 '13 at 21:37
  • Just have to take care with file names with funny characters... and the ${FILE#dev-} is a bashishm, AFAIU (definitely not in /bin/sh on Solaris way back).
    – vonbrand
    Feb 11 '13 at 23:38
  • 1
    @vonbrand, ${FILE#dev-} is not Bourne, but is POSIX (was introduced by ksh, not bash). You need -- for ln to mark the end of options for a * pattern, or better, use a dev-* pattern. The code as it is would create symlinks to themselves in every subdirectory of the current directory whose name doesn't start with dev-. See also the notes in my answer. Feb 12 '13 at 6:48
  • Thanks to all, for your help & explanations. Adding dev-* instead of * worked as intended here - as the code stands above it tries to create symlinks for every file.
    – gbentley
    Feb 13 '13 at 19:35

I usually use a brief one-liner.

for file in dev-*.php; do ln -s $file $(echo "$file" | sed 's/^dev-//'); done

This cycles through the 'dev-*.php' files, getting the new name without 'dev-', then creating the symlink.


With zsh, you'd do:

autoload zmv # typically in ~/.zshrc
zmv -Lsv 'dev-(*.php)' '$1'

With bash or other POSIX shells (including zsh):

for f in dev-*.php; do
  ln -s "$f" "${f#dev-}"

Note that if site.php exists and is a directory (or a symlink to a directory), then you may end up with a dev-site.php symlink inside it. With GNU ln you could add the -T option to guard against that (with zmv use -o -T to pass the -T option down to ln).

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.