10

I'm looking for a single linux command that allows me to do the equivalent of this:

cp /some/path/file /another/path/ && ln -sf /another/path/file /some/path/

If there isn't one, what's the best way to do this for a bunch of files?

8
  • I don't know Bash scripting well enough to write it, but my solution would be to just write a script and call it something catchy like cpln
    – Unkwntech
    May 14 '09 at 8:33
  • 1
    Shouldn't cp be mv? May 14 '09 at 8:41
  • No. The -f option to ln takes care of that.
    – innaM
    May 14 '09 at 9:09
  • 1
    try it on a 10GB file
    – hayalci
    May 18 '09 at 18:49
  • 2
    @HelloGoodbye You're confusing && with &. As written, the line does check the return value of cp and only runs the second part if it succeeded.
    – itsadok
    May 10 '15 at 12:33
7

A small note, is that you could use ln both times to make the command not actually move the data (assuming both paths are on the same filesystem).

ln /some/path/file /another/path/ && ln -sf /another/path/file /some/path/

But I assume that you want to move the content of /some/path/ to an other disk, and then create links to the new files so "no one" notices.

for f in `ls /some/path/`; do ln /some/path/$f /another/path/ && ln -sf /another/path/$f /some/path; done

Wrapping it in a bash function:

function cpln {
    for f in `ls $1`
    do
        ln $1/$f $2 && ln -sf $2/$f $1
    done
}
4
  • Is there a way to make this work if what I'm moving happens to be a directory?
    – tladuke
    Aug 9 '12 at 18:50
  • How does this move the actual file on disk?
    – Ibrahim
    Dec 6 '12 at 10:55
  • Ibrahim: the data doesn't move, it just updates the pointers in the directory.
    – Mr Shark
    Dec 10 '12 at 10:13
  • tladuke: Yes and no. Since the directory is much smaler on disk, there is no need for the ln trick (which don't work for directorys), just do a mv :-)
    – Mr Shark
    Dec 10 '12 at 10:16
2

Theres my script you could use (takes two parameters /some/path/file and /another/path/ ):

#!/bin/bash
cp $1 $2
if [ "$?" -ne "0" ]; then
    echo "Some error"
    exit 1
    fi
ln -sf $2/${1##*/} ${1%/*}
1
  • Cool trick with the string manipulations, never saw that before. Thanks!
    – itsadok
    May 17 '09 at 11:17
1

Seriously, I thought this was a really easy question.

Here's what I can do in perl:

#!/bin/perl
# Usage: cpln TARGETDIR SOURCE...
# Example: find tree/ -type f | xargs cpln commands/

$target = shift;

foreach(@ARGV) {
    m[(.*)/([^/]+)];
    system("cp $_ $target");
    system("ln -sf $target/$2 $1/");
}

I was hoping for something more elegant, but I guess I'll use that.

1
  • 1
    To do it "in Perl," you should use File::Copy (or similar) and symlink(). Perl is not shell; avoid system(), and especially avoid passing whole command lines to system() (e.g., what if an argument contains a space?). Either way, always, always, ALWAYS check return values. May 14 '09 at 14:53

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.