====================================== Symbolic Links - Soft Links - Symlinks ====================================== -Ian! D. Allen - idallen@idallen.ca - www.idallen.com Reference: http://www.nixtutor.com/freebsd/understanding-symbolic-links/ Advanced reference: http://linuxgazette.net/105/pitcher.html In contrast to "hard links", symbolic links are called "soft links" or "symlinks". They were invented to solve the limitation of not being able to make hard links to directories. Symbolic links can link to *anything*, even directories, so they can give multiple names to directories. The process of following a symbolic link reference to its actual file system target is called "dereferencing" the symbolic link. Some commands automatically dereference symlinks; many do not. Symbolic links were brought to Unix at Berkeley (BSD Unix) in the 1980s. They are now available in Microsoft NTFS as of Wiindows Vista, 30 years later. See: http://www.howtogeek.com/howto/windows-vista/using-symlinks-in-windows-vista/ Second-class citizens --------------------- Symlinks are similar to Windows/Macintosh aliases and have some of the same limitations. They are secondary names for inodes, because they don't change the link count field and they can break if you rename or delete the target of the link. Symlinks are second-class file system objects and many programs - especially programs that recursively walk directory trees such as "find", "tree", "cp -r", and "ls -R" - don't follow them, so they don't cause infinite loops in the file system. Creating and Listing Symlinks ----------------------------- You create a symbolic link using the "-s" option to the link command, and symbolic links are identified by leading "l" characters in the output of "ls -l": Symlink Syntax: ln -s SOURCE DESTINATION(or TARGET) $ ln -s /etc/passwd soft $ ln /etc/passwd hard $ ls -li soft hard /etc/passwd 10839 -rw-r--r--. 2 root root 2047 2012-03-18 09:45 /etc/passwd 10839 -rw-r--r--. 2 root root 2047 2012-03-18 09:45 hard 136193 lrwxrwxrwx. 1 alleni alleni 11 2012-03-18 18:41 soft -> /etc/passwd $ wc soft hard /etc/passwd 42 62 2047 soft 42 62 2047 hard 42 62 2047 /etc/passwd 126 186 6141 total You will note an immediate difference between a symlink and a hard link is that a symnlink is not simply another name for the same inode. A symlink gets its own inode (in which to store the link target name), which means it gets its own file type, permissions, owner, group, and modify time. A symbolic link is like a file pointing to another pathname. Creating the symlink doesn't affect the link count of the link target. The owner, group, and permissions of a symlink are ignored and can't be changed. The only thing that matters in a symlink is the target name. You can create and remove symbolic links without affecting the target of the links. Indeed, the target pathnames know nothing about symbolic links and are completely unaffected by them. The link counts do not change. Relative Path Targets --------------------- If the target (destination) of the symlink is a relative pathname (does not start with a slash), the actual target is taken as relative to the directory storing the symlink, e.g. $ ln -s bar /tmp/foo # "bar" is relative to "/tmp/", so "/tmp/bar" $ ln -s .. /tmp/foo # ".." is relative to "/tmp/", so "/tmp/.." $ ln -s . /tmp/foo # "." is relative to "/tmp/", so "/tmp/." $ ln -s a/b /tmp/foo # "a/b" is relative to "/tmp/", so "/tmp/a/b" To find the actual target of relative symlinks, take off the basename of the symlink and append the symlink target in its place. More examples showing how "rbash" and "sh" are synonyms for "bash": $ ls -l /bin/*sh -rwxr-xr-x 1 root root 664084 Apr 21 2006 /bin/bash lrwxrwxrwx 1 root root 4 Aug 22 18:42 /bin/rbash -> bash lrwxrwxrwx 1 root root 4 Aug 22 18:42 /bin/sh -> bash symlink /bin/rbash: target "bash" is relative to "/bin/", so "/bin/bash" symlink /bin/sh: target "bash" is relative to "/bin/", so "/bin/bash" Using "." (dot) as a Symlink Target ----------------------------------- A symlink containing "." refers to the directory it is in, and can make a directory name "disappear" in a pathname: $ ln -s . /usr/local # "." is relative to "/usr/" so "/usr/." $ ls -l /usr/local/bin # same as /usr/./bin or /usr/bin If you have a program that insists on using /usr/local/bin but you want it to use simply /usr/bin, you can make the "local" disappear in your file system by making /usr/local a symlink to "." in your system. Dangling Symlinks ----------------- You can put any text you like into the target of a symbolic link. The target doesn't have to exist or even look like a file name. If the target doesn't resolve to an existing file system object, the program accessing the symlink will give an appropriate error: $ ln -s nosuchfile bar $ ls -l bar lrwxrwxrwx 1 idallen idallen 10 Feb 9 10:42 bar -> nosuchfile $ cat bar cat: bar: No such file or directory $ ln -s "This is some random text that fits into the symlink." foo $ ls -l foo lrwxrwxrwx. 1 alleni alleni 52 2012-03-18 19:25 foo -> This is some random text that fits into the symlink. $ cat foo cat: foo: No such file or directory Note that the error message always uses the name of the symlink, not the name of the symlink target. Only by later examining the pathname would you discover that both "foo" and "bar" were actually symlinks to nonexistent files. A non-functional symlink is called a "broken" or "dangling" symlink; it's a link to something that doesn't exist. Too many levels of symbolic links --------------------------------- The system will only process a limited number of symbolic link references when resolving a pathname (at least eight levels, usually more). If you create a symlink that links back to itself, either directly or via another symlink, you get an error that the link count has been exceeded: $ ln -s foo foo $ cat foo cat: foo: Too many levels of symbolic links Commands and Symlinks: ls, rm, chmod, chown, find ------------------------------------------------- Most commands that do not dereference symbolic links can be made to do so with appropriate command line options - see the man pages. The "ls" command treats symbolic links somewhat inconsistently, in that saying "ls -l symlink" will show the symlink itself but "ls symlink" and "ls -R symlink" will access the target of the symlink, and if the target is a directory you get to see the contents of the target directory. The "rm" command does not follow symbolic links. "rm -r symlink" removes only the symlink, not the target. Both "chmod" and "chown" do follow symlinks given on the command line, but ignore symlinks discovered in a recursive descent (-R). The "find" command does not follow symbolic links. Avoiding symbolic links using trailing dot (".") ------------------------------------------------ Many commands behave differently if they operate on symlinks or real directories. Sometimes you want the directory behaviour, but all you have is the symbolic link name and you don't get what you wanted. For example, you might want to see the list of system mailboxes under /var/mail, but on this system /var/mail isn't a directory, it's a symlink, and so you don't hget what you want: $ ls -l /var/mail lrwxrwxrwx. 1 root root 10 2011-09-02 09:43 /var/mail -> spool/mail The trick is to append "/." to the symbolic link name to turn it into a real directory so that "ls" shows the real contents: $ ls -l /var/mail/. total 4 -rw-rw----. 1 alleni mail 0 2011-09-02 10:19 alleni -rw-rw----. 1 flanders mail 0 2012-03-11 03:48 flanders -rw-rw----. 1 homer mail 0 2012-03-11 03:48 homer -rw-------. 1 root root 831 2011-09-26 01:52 root -rw-rw----. 1 rpc mail 0 2011-09-02 09:48 rpc A basename of "." (or "..") can never be a symbolic link; it's always a real directory, so if "foo" is a symlink to a directory, then "foo/." is the real directory that is the target of the symlink, and commands "ls -l foo" and "ls -l foo/." give very different results, as do "find foo" and "find foo/.": $ ln -s / foo # foo is a symlink to the ROOT $ ls -ld foo # using "foo" shows only the symbolic link "foo" itself lrwxrwxrwx. 1 alleni alleni 1 2012-03-18 20:07 foo -> / $ ls -ld foo/. # "." is inside ROOT; shows the actual ROOT directory dr-xr-xr-x. 23 root root 4096 2012-03-11 03:49 foo/. $ find foo # using "foo" finds only the symbolic link "foo" itself foo $ find foo/. # finds every file on the whole system from the ROOT down foo/. foo/./var [...many many file names here...] If you want to be sure that a directory pathname is *not* a symbolic link (or you don't know if the name might be a symbolic link now or in future), always append "/." to the name to get the actual directory instead of the link name. Summary of Symbolic Links (Symlinks) ------------------------------------ - similar to Windows/Mac aliases, but they work even for directories - can symlink to anything, even directories - can symlink to nonexistent pathnames - a "dangling symlink" Q: How do you create a symlink named /tmp/foo that contains the path "/bin"? A: ln -s /bin /tmp/foo Q: What does this do: ln -s foo bar ; ln -s bar foo ; cat foo A: cat: foo: Too many levels of symbolic links -- | Ian! D. Allen - idallen@idallen.ca - Ottawa, Ontario, Canada | Home Page: http://idallen.com/ Contact Improv: http://contactimprov.ca/ | College professor (Free/Libre GNU+Linux) at: http://teaching.idallen.com/ | Defend digital freedom: http://eff.org/ and have fun: http://fools.ca/