% Symbolic Links -- Soft Links -- Symlinks % Ian! D. Allen -- -- [www.idallen.com] % Fall 2016 - September to December 2016 - Updated 2017-03-09 09:26 EST - [Course Home Page] - [Course Outline] - [All Weeks] - [Plain Text] Introduction ============ - Ubuntu (CLS) manual page: `man 7 symlink` - Reference: - Advanced reference: 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. Symbolic links were brought to Unix at Berkeley (BSD Unix) in the 1980s. They are now available in Microsoft NTFS as of Windows Vista, 30 years later. See: Second-class citizens ===================== Symlinks are similar to Windows/Macintosh aliases and have some of the same limitations. They are secondary names, because they don't change the link count field of the things they link to and they can stop working if you rename or delete the actual file system object that is 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 `ln`, and symbolic links are identified by leading `l` characters in the output of `ls -l`: Symlink Syntax (RTFM): ln -s TARGET LINK_NAME $ date >foo $ ln foo hard # hard link $ ln -s foo soft # symbolic or soft link $ ls -li foo hard soft 1442426 -rw-rw-r-- 2 alleni alleni 29 Mar 5 06:50 foo 1442426 -rw-rw-r-- 2 alleni alleni 29 Mar 5 06:50 hard 1442454 lrwxrwxrwx 1 alleni alleni 3 Mar 5 06:50 soft -> foo $ wc foo hard soft 1 6 29 foo 1 6 29 hard 1 6 29 soft You will note an immediate difference between a symlink and a hard link is that a symlink is not simply another name for the same inode. A symlink gets its own inode that is used 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 the symlink inode itself are ignored and don't matter. The only thing that matters in a symlink is the target name. (The `root` user can change the owner and group of a symlink on some systems, but nothing can change the permissions of a symlink. Read the `man` pages for the `chmod` and `chown` commands to see how they dereference symlinks.) You can create and remove symbolic links without affecting the file system object that is the target of the link. Indeed, the target pathnames know nothing about symbolic links and are completely unaffected by them. Their link counts do not change. Only hard links change link counts. The TARGET of the symlink does not change ----------------------------------------- Creating symbolic links with `ln -s`: The first pathname argument is the **TARGET** of the symlink; it is not relative to or affected by your current directory; it's just a piece of text. Any one of the `ln` commands below would create exactly the same symlink `bar -> foo` in the `d` directory: - `$ mkdir -p a/b/c/d ; date >a/b/c/d/foo` - 1. `$ ln -s foo a/b/c/d/bar` - 2. `$ cd a ; ln -s foo b/c/d/bar` - 3. `$ cd a/b ; ln -s foo c/d/bar` - 4. `$ cd a/b/c ; ln -s foo d/bar` - 5. `$ cd a/b/c/d ; ln -s foo bar` The first pathname argument is the **TARGET** of the symlink; it doesn't change when you change directories. The second pathname argument is where you want to create the symlink, and of course if it is a relative pathname then it changes depending on your current directory. Dereferencing Symbolic Links ============================ 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, especially commands that recursively walk file systems (e.g. `find`, `cp -r`, `tree`, etc.). Some commands dereference symlinks when they are given on the command line as arguments, but do not dereference them when they are encountered in a recursive walk of the file system (e.g. `chmod`, `chown`, etc.). Dereferencing Absolute Path Symlinks ------------------------------------ If the target contained in the symlink is an absolute pathname (i.e. starts with a slash), then dereferencing the symlink means going to that absolute pathname. **Example 1**: Dereferencing an absolute path symlink: $ cd /tmp $ ln -s /etc/passwd soft # the target is an absolute pathname $ ls -l soft lrwxrwxrwx 1 alleni alleni 11 2012-03-18 18:41 soft -> /etc/passwd Above, the symbolic link pathname `soft` is a symbolic link to the target `/etc/passwd` that is itself an absolute pathname. Referring to `soft` is the same as referring to `/etc/passwd` (for commands that follow symlinks): $ cd /tmp $ ln -s /etc/passwd soft # the target is an absolute pathname $ ls -l soft lrwxrwxrwx 1 alleni alleni 11 2012-03-18 18:41 soft -> /etc/passwd $ wc soft # same as wc /etc/passwd $ wc /tmp/soft # same as wc /etc/passwd $ wc ../tmp/soft # same as wc /etc/passwd $ wc ../../tmp/soft # same as wc /etc/passwd **Example 2**: Dereferencing an absolute path symlink: $ cd $ ln -s ~idallen/public_html/teaching/cst8207/16f/notes newnotes $ ls -l newnotes lrwxrwxrwx 1 alleni alleni 52 Mar 5 06:00 newnotes -> /home/idallen/public_html/teaching/cst8207/16f/notes Above, the symbolic link pathname `newnotes` in my home directory is a symbolic link to the target `~idallen/public_html/teaching/cst8207/16f/notes` that is itself an absolute pathname (because the shell replaces `~idallen` with `/home/idallen` when it reads the leading tilde). Referring to `newnotes` is the same as referring to `/home/idallen/public_html/teaching/cst8207/16f/notes` (for commands that follow symlinks): $ cd $ ln -s ~idallen/public_html/teaching/cst8207/16f/notes newnotes $ ls -l newnotes lrwxrwxrwx 1 alleni alleni 52 Mar 5 06:00 newnotes -> /home/idallen/public_html/teaching/cst8207/16f/notes $ ls newnotes # same as next command: $ ls /home/idallen/public_html/teaching/cst8207/16f/notes $ less newnotes/week01notes.txt # same as next command: $ less /home/idallen/public_html/teaching/cst8207/16f/notes/week01notes.txt **Example 3**: Dereferencing chains of absolute path symlinks: $ which vi /usr/bin/vi $ ls -l /usr/bin/vi lrwxrwxrwx 1 root root 20 Sep 7 2012 /usr/bin/vi -> /etc/alternatives/vi $ ls -l /etc/alternatives/vi lrwxrwxrwx 1 root root 16 Jan 29 2013 /etc/alternatives/vi -> /usr/bin/vim.gtk $ ls -l /usr/bin/vim.gtk -rwxr-xr-x 1 root root 2387776 May 4 2012 /usr/bin/vim.gtk $ file /usr/bin/vim.gtk /usr/bin/vim.gtk: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x9044e1c3d931c29425be2a76488fa95196ee069e, stripped Above, the pathname `/usr/bin/vi` is a symlink containing absolute path `/etc/alternatives/vi`, which is itself a symlink containing absolute path `/usr/bin/vim.gtk`, which is an executable program. $ which pico /usr/bin/pico $ ls -l /usr/bin/pico lrwxrwxrwx 1 root root 22 Sep 7 2012 /usr/bin/pico -> /etc/alternatives/pico $ ls -l /etc/alternatives/pico lrwxrwxrwx 1 root root 9 Sep 7 2012 /etc/alternatives/pico -> /bin/nano $ ls -l /bin/nano -rwxr-xr-x 1 root root 191960 Dec 3 2010 /bin/nano $ file /bin/nano /bin/nano: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, BuildID[sha1]=0x9611a8270fb6d94668dce9de67be6a633325b558, stripped $ which nano /usr/bin/nano $ ls -l /usr/bin/nano lrwxrwxrwx 1 root root 9 Sep 7 2012 /usr/bin/nano -> /bin/nano Above, we see that the command `pico` is, through a chain of symbolic links, actually the same program file as the command `nano`. Putting an absolute path into a symlink means that accessing the symlink accesses whatever is at the absolute path instead (for commands that follow symlinks). Dereferencing Relative Path Symlinks ------------------------------------ If the target contained in the symlink is a relative pathname (i.e. the target in the symlink does not start with a slash), then dereferencing the symlink is done *relative to the directory containing the symlink*. The actual file system object referenced by the symlink is found *relative to the directory containing the symlink*. To find the actual object referenced by a relative symlink, use the directory name containing the symlink and append the symlink target (the relative path) onto it, e.g.: $ ln -s bar /tmp/foo # "bar" is a relative target (no leading slash) $ ls -l /tmp/foo lrwxrwxrwx 1 alleni alleni 3 Mar 5 05:57 /tmp/foo -> bar $ cat /tmp/foo # same as cat /tmp/bar Above, any reference to to the symlink `/tmp/foo` finds that the symlink `foo` contains the relative (not absolute) path `bar`, so the resulting pathname for `/tmp/foo` is taken to be the directory containing the symlink (`/tmp`) with the relative path `bar` appended, giving `/tmp/bar`: $ ln -s bar /tmp/foo # "bar" is a relative target (no leading slash) $ ls -l /tmp/foo lrwxrwxrwx 1 alleni alleni 3 Mar 5 05:57 /tmp/foo -> bar $ cat /tmp/foo # same as cat /tmp/bar $ cat ../tmp/foo # same as cat ../tmp/bar $ cat ../../tmp/foo # same as cat ../../tmp/bar The directory containing the symlink may be the current directory: $ ln -s bar /tmp/foo # "bar" is a relative target (no leading slash) $ ls -l /tmp/foo lrwxrwxrwx 1 alleni alleni 3 Mar 5 05:57 /tmp/foo -> bar $ cd /tmp $ cat foo # same as cat bar because foo -> bar In the `cat foo` line above, `foo` is a relative pathname, and relative pathnames are always relative to the current directory. The current directory is `/tmp`, so `cat foo` (a relative path) is the same as `cat /tmp/foo` (the absolute path). Since the `foo` in `/tmp/foo` is itself a symbolic link with a relative target `bar` inside it, the rule is to take the containing directory `/tmp` and append the relative target `bar` to it, giving `/tmp/bar`. So `cat foo` is the same as `cat bar`. Another example using the relative target `..`: $ ln -s .. /tmp/foo # ".." is a relative target (no leading slash) $ ls -l /tmp/foo lrwxrwxrwx 1 alleni alleni 2 Mar 5 06:00 /tmp/foo -> .. $ ls /tmp/foo # same as ls /tmp/.. $ cd /tmp $ ls foo # same as ls .. because foo -> .. Another example using the relative target `.`: $ ln -s . /tmp/foo # "." is relative target (no leading slash) $ ls -l /tmp/foo lrwxrwxrwx 1 alleni alleni 1 Mar 5 06:00 /tmp/foo -> . $ ls /tmp/foo # same as ls /tmp/. $ cd /tmp $ ls foo # same as ls . because foo -> . Another example using the relative target `a/b`: $ ln -s a/b /tmp/foo # "a/b" is a relative target (no leading slash) $ ls -l /tmp/foo lrwxrwxrwx 1 alleni alleni 3 Mar 5 06:00 /tmp/foo -> a/b $ ls /tmp/foo # same as ls /tmp/a/b $ cd /tmp $ ls foo # same as ls a/b because foo -> a/b More examples showing how `rbash` and `sh` are synonyms for `bash` and `dash`: $ ls -l /bin/*sh -rwxr-xr-x 1 root root 959120 Mar 28 2013 /bin/bash -rwxr-xr-x 1 root root 109768 Mar 29 2012 /bin/dash lrwxrwxrwx 1 root root 4 Mar 28 2013 /bin/rbash -> bash lrwxrwxrwx 1 root root 4 Sep 7 2012 /bin/sh -> dash lrwxrwxrwx 1 root root 7 Nov 16 2012 /bin/static-sh -> busybox Above, pathname `/bin/rbash` is a symlink with relative target `bash`, so to dereference the relative symlink `/tmp/rbash` we take the directory containing the symlink (`/bin`) and we append the relative target path `bash` giving `/bin/bash`. So `/bin/rbash` is really `/bin/bash`. Above, pathname `/bin/sh` is a symlink with relative target `dash`, so to dereference the relative symlink `/bin/sh` we take the directory containing the symlink (`/bin`) and we append the relative target path `dash` giving `/bin/dash`. So `/bin/sh` is really `/bin/dash`. 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. Most Unix/Linux systems give you least eight levels, and the [Course Linux Server] currently supports 40. 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 $ ls -l foo lrwxrwxrwx 1 alleni alleni 3 Mar 5 07:12 foo -> foo $ cat foo cat: foo: Too many levels of symbolic links $ ln -s a b $ ln -s b a $ ls -l a b lrwxrwxrwx 1 alleni alleni 1 Mar 5 07:11 a -> b lrwxrwxrwx 1 alleni alleni 1 Mar 5 07:11 b -> a $ cat a cat: a: Too many levels of symbolic links $ cat b cat: b: Too many levels of symbolic links As mentioned above, the [Course Linux Server] can currently (March 2017) resolve a chain of up to 40 symbolic links. Commands and Symlinks: `ls`, `rm`, `chmod`, `chown`, `find`, `grep` =================================================================== Most commands that do not normally dereference (follow) 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 by default. Using `grep` with the "recursive" option *does* follow symlinks (and there is no way to prevent this -- be careful of file system loops!). Avoiding symbolic links using trailing dot (`.`) ================================================ As noted in the previous section, 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 get the contents of the directory when you `ls`, all you get is the symlink: $ 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/. -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 directory name to get the actual directory instead of the link name. (Of course this does *not* work for file names, since you can't append `/.` to a file.) Summary of Symbolic Links (Symlinks) ==================================== - similar to Windows/Mac aliases, but they work even for directories - you can symlink to anything, even directories - you can symlink to nonexistent pathnames -- a "dangling symlink" Mini test: Q: How do you create a symlink named /tmp/foo that contains the path "/bin"? A: ln -s /bin /tmp/foo $ ls -l /tmp/foo lrwxrwxrwx 1 idallen idallen 4 Oct 22 12:22 /tmp/foo -> /bin Q: What does this do: ln -s foo bar ; ln -s bar foo ; cat foo A: cat: foo: Too many levels of symbolic links $ ls -l foo bar lrwxrwxrwx 1 idallen idallen 3 Oct 22 12:21 bar -> foo lrwxrwxrwx 1 idallen idallen 3 Oct 22 12:21 foo -> bar -- | Ian! D. Allen, BA, MMath - 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/ [Plain Text] - plain text version of this page in [Pandoc Markdown] format [www.idallen.com]: http://www.idallen.com/ [Course Home Page]: .. [Course Outline]: course_outline.pdf [All Weeks]: indexcgi.cgi [Plain Text]: 460_symbolic_links.txt [Course Linux Server]: 070_course_linux_server.html [Pandoc Markdown]: http://johnmacfarlane.net/pandoc/