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, 2009 at 8:33
  • 1
    Shouldn't cp be mv? May 14, 2009 at 8:41
  • No. The -f option to ln takes care of that.
    – innaM
    May 14, 2009 at 9:09
  • 1
    try it on a 10GB file
    – hayalci
    May 18, 2009 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, 2015 at 12:33

3 Answers 3

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, 2012 at 18:50
  • How does this move the actual file on disk?
    – Ibrahim
    Dec 6, 2012 at 10:55
  • Ibrahim: the data doesn't move, it just updates the pointers in the directory.
    – Mr Shark
    Dec 10, 2012 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, 2012 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, 2009 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
  • 2
    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, 2009 at 14:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .