ln -s
The reason that ln -s file target is confusing is that, even though it is consistent with cp and mv, unlike those commands, it is not consistent english language.
Compare the english sentence:
Copy a file to a place
with the shell command
cp a_file a_place
Notice how they're the same way round? Now compare the english
Create a link thingy to the file boing
In english, we say this the other way round, whereas the shell command is still in the same direction as cp and mv:
ln this_file_exists make_this_point_to_that
and that's why it is confusing you sometimes.
A solution (or two)
I present, for your use, two very simple perl scripts which I've personally used for years to solve this problem. Choose one, stick it in your ~/bin (unless, of course, you've been scared by 'Why putting ~/bin or . in your $PATH is a bad idea').
They both rely on the fact that when you are creating links, you generally want to create a link that doesn't exist, to a file that does. Both these scripts accept the arguments either way round and create the link the way that makes sense. The downside of this is that you can't create a new link over an old one without rm-ing it first.
The first one is dead simple. It checks which way round you meant and passes them off to the real ln program. It will handle hard links or symlinks (with the -s option) but not any other option since they tend to do with overwriting old links, and we can't do that*.
#!/usr/bin/perl
if ($ARGV[0] eq '-s'){
$s="-s";
shift;
}
if (-e $ARGV[0]){
die ("Cannot overwrite existing file") if -e $ARGV[1];
`ln $s $ARGV[0] $ARGV[1]`;
}else{
die ("Target file does not exist") unless -e $ARGV[1];
`ln $s $ARGV[1] $ARGV[0]`;
}
and the other is slightly more interesting in that it does the symlinks itself, without calling the old
ln program. The upshot of this is that you
could replace the /usr/bin/ln on your system with it. But I
really wouldn't recommend it.
#!/usr/bin/perl
use File::Spec("rel2abs");
if ($ARGV[0] eq '-s'){
shift;
}
if (-e $ARGV[0]){
die ("Cannot overwrite existing file") if -e $ARGV[1];
symlink (File::Spec->rel2abs($ARGV[0]),File::Spec->rel2abs($ARGV[1]));
}else{
die ("Target file does not exist") unless -e $ARGV[1];
symlink (File::Spec->rel2abs($ARGV[1]),File::Spec->rel2abs($ARGV[0]));
}
* I did play with the idea of checking to see if one file is a symlink (if they both already exist) and overwriting that one, but it seems a big ambiguous and dangerous.
Thanks to OldMiner for helping me sort the confusing nature of my w/u :-)