I am having a hard time understanding symbolic links. I believe I understand the basic premise, it is an alias essentially.
However, does it depend on what working directory you are in when you make it on how it works, assuming you are letting that current working directory play into the making of the symbolic link?
The current command I am using is ln -s
I have a few projects in GitHub, some of them are simple little scripts I have written that I store in ~/bin. ~/bin is in my $PATH environment variable for easy access to calling these scripts:
$echo $PATH
/Users/me/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/git/bin
I just noticed that in my install of git it looks like /usr/local/git/bin
has been appended to my $PATH. For the time being, I am going to pretend that didn't happen.
For example:
( hist
is a simple script that shows stats on my most recently used commands )
#/bin/bash
history | awk '{CMD[$2]++;count++;}END { for (a in CMD)print CMD[a] " " CMD[a]/count*100 "% " a;}' | grep -v "./" | column -c3 -s " " -t | sort -nr | nl | head -n10
$hist
1 115 23% l
2 58 11.6% cd
3 44 8.8% ls
4 29 5.8% git
5 14 2.8% sudo
6 13 2.6% locate
7 12 2.4% open
8 11 2.2% wc
9 10 2% dt
10 9 1.8% rm
If I perform this action:
$cd ~/bin
$pwd
$/Users/me/bin
$ln -s hist ~/Desktop/hist
$ls -la ~/Desktop/
$ls -la | grep hist
lrwxr-xr-x 1 me staff 4 Sep 15 21:15 hist -> hist
$cd ~/Deskop
$hist
The command words, but the listing of hist -> hist
concerns me, it provides no information as to where the real source is. I'm not sure I can move the file elsewhere and it will still work.
So I have recently gotten in the habit of not using any expansion tokens when making symbolic links. Meaning no more ~
and the like.
I only even had to begin doing this as I started using GitHub, and was making repositories of my .bash_profile
, .bashrc
, and .bash_history
. It was becoming a lot of work every time I made a change to my .bash_profile
to then cp
it from my local repository to ~/bin
, and then run source ~/bin/.bash_profile
What is the proper procedure for this with ln -s
, or is it purely a matter of preference, and the end results will always work the same.
The good news is I learned about the -F flag to ln
so I no longer get an error if I hit the filename that is the destination. The -F flag will tell ln
to write over it, saving me time of mv
'ing the file and then running the ln -s
command.
This is what my ~/bin looks like right now, with many removed to keep it simple:
$l
total 56
lrwxr-xr-x 1 me staff 53 Sep 15 20:40 hist -> /Users/me/Documents/me/git-projects/hist/hist
lrwxr-xr-x 1 me staff 57 Sep 15 20:41 lcaser -> /Users/me/Documents/me/git-projects/lcaser/lcaser
lrwxr-xr-x 1 me staff 70 Sep 10 05:12 mate -> /Applications/TextMate 1.x.app/Contents/SharedSupport/Support/bin/mate
lrwxr-xr-x 1 me staff 56 Sep 15 20:42 tart -> /Users/me/Documents/me/git-projects/tart/tart.sh
lrwxr-xr-x 1 me staff 69 Sep 15 20:44 watchinstall -> /Users/me/Documents/me/git-projects/watchInstall/watchInstall
Consider:
ln -s target linkname
The complication occurs only when target
is specified by a relative path. If it is, then the path is relative to the directory that holds the file linkname
. The currect working directory is always ignored.
As an example, consider
ln -s hist ~/Desktop/hist
This command creates a link named hist
in ~/Desktop
. Since no path is given for the target, the target is interpreted as also being in the directory ~/Desktop
. In this case, that means the the link hist
points to itself.
As another example, consider
cd /var/tmp
ln -s ../hist ~/Desktop/hist
This will create a link from ~/Desktop/hist
to ~/hist
because the ../
is interpreted relative to the directory that holds the link, ~/Desktop
. The directory that we are in when the ln
command is executed and the directory that we are in when we access /Desktop/hist
are both irrelevant.
ln
does not care what you use for target
when the command is issued: it can be arbitrary text. The value of target
is not intepreted until an attempt is made to access linkname
. Consider:
$ ln -s "mary had a little lamb" ~/file1
$ ls -alt ~/file1
lrwxrwxrwx 1 user group 22 Sep 15 21:47 /home/user/file1 -> mary had a little lamb
$ cat ~/file1
cat: /home/user/file1: No such file or directory
If we want we can later create that file:
$ echo this is a test >~/"mary had a little lamb"
$ cat ~/file1
this is a test
Again, the existence of the target is only checked when an attempt is made to access the link.
This behavior is documented in man ln
:
Symbolic links can hold arbitrary text; if later resolved, a relative link is interpreted in relation to its parent directory.