Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

My situation has 2 directories: /blah/d01 and /blah/d02

$ls -l /blah/d01
fa -> a
fb -> b
fc -> c

and I want to copy fa, fb, fc to /blah/d02, and as a result:

$ls -l /blah/d02
fa -> ../d01/a
fb -> ../d01/b
fc -> ../d01/c

the point is, I want to do something like cp --{some magic attr} /blah/d01/f* /blah/d02/ to make this happen.



I settled with a bash script:

#! /bin/bash
for i in $@; do echo $i && [ -L $i ] && ln -s $(dirname $i)/$(readlink $i) $(basename $i); done

which make newlinks based on old ones(make sure that they use relative path)


I found my last script works but the link path would be awkwardly long(full with strange relative paths) after copy symlinks from a to b and from b to c, so I added something to cleanup relative path, and the script ends:

#! /bin/bash
function relpath {

  while [ "${target#$common_part}" = "${target}" ]; do
    common_part=$(dirname $common_part)

  echo ${back}${target#$common_part/}

for i in $@; do echo $i && [ -L $i ] && ln -s $(relpath $PWD $(readlink -f $i)); done
share|improve this question
up vote 1 down vote accepted

As those symlinks are created w/o full qualified path, that's a thing hard to do with cp. But you could rather create new ones at the target:

for i in *; do [ -L $i ] && cd blah && ln -s ../$i $i && cd -; done

Short explanation:

  • for i in *: Loop over the list of files/directories in the currend location
  • do: encapsulate what has to be done
  • [ -L $i ] &&: only continue if the current entry is a symbolic link
  • cd blah && ln -s ../$i $i && cd -: change to blah and create symlinks to the original location

That's not yet exactly what you want (as it symlinks the symlinks). So we will modify it a bit:

for i in *; do [ -L $i ] && cd blah && ln -s ../$(readlink ../$i) $i && cd -; done

The added construct $(readlink ../$i) evaluates the object the link points to, and places the result there instead. Et voila -- the result is what you were looking for.

Note that I simplified your request a little (making it as if you'd just want to copy the symlinks to a subdirectory), so it is easier to follow. You have to adjust it either, as I do not assume your real directory is called blah :)

share|improve this answer
@lzzy that's really decent of you, thanks! maybe I should save this script :D – tdihp Jul 24 '12 at 9:25
@tdihp good idea. And don't forget to accept (or at least up-vote) the answer if you like it :) – Izzy Jul 24 '12 at 9:50

I think you should use full path instead relative path as

fx -> /full/path/to/x

So when you copy link it will always show x.

share|improve this answer
Doing this your way is acceptable, despite the trouble to provide abs path when ln ... thanks – tdihp Jul 24 '12 at 9:45
And sadly, I just find out that I want it relative, to work under nfs, too... – tdihp Jul 24 '12 at 10:04

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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