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?

  • 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? – Bart van Heukelom 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
}
| improve this answer | |
  • 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%/*}
| improve this answer | |
  • 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.

| improve this answer | |
  • 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. – John Siracusa 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.