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

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 :)

  • @lzzy that's really decent of you, thanks! maybe I should save this script :D
    – tdihp
    Jul 24 '12 at 9:25

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.

  • 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 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.