1

As we all know, the ln command creates a link, with the default being a hard link and the -s option creating a symlink. The general syntax is ln [-s] OLD NEW, where OLD is the file you are linking to and NEW is the new file you are creating. Hard links can not be created for directories, as a hard link could be created between folders inside each other & I suppose computers do not yet have the resources to check for this without a SERIOUS slowdown.

When creating the link, the path of both files must be written out, and can be absolute or relative. You can mix relative & absolute filepaths, i.e. have a relative path for the new file/folder & an absolute path for the old one. When creating a hard link with a relative path, the paths of both files are relative to the current folder, while for a symbolic link the path of the linked-to file/folder is relative to its parent folder but the path of the old file/folder is relative to the current folder. Why this is is "relative" to my question.

For example, say we am in the HOME folder, /home/user, also known as ~, and create 2 folders, new and new2, with the file file in the folder new. If we try ln -s new/file new2/file, the result is a broken link from ~/new2/file to the currently nonexistent ~/new2/new/file. However, if we instead run ln -s ../new/file new2/file, we get the expected result, which is a link from ~/new2/file to ~/new/file.

So, my question:

Why is the file path for the OLD file/folder of a symlink relative to its parent, while the other 3 paths (hard link OLD, NEW files, symlink NEW file/folder) are relative to the current folder?

All this is on Fedora, but I'm sure it applies to most UNIX-based OS's.

EDIT E Carter Young seems to hit the nail on the head with regard to my 2nd question (as well as my 1st question, which was wrong anyway). It seems that for a symbolic link, the target doesn't have to exist yet, so the system has to make its path relative to the link rather than the current directory. However, why can't the shell parse out that path when you're running the command, rather than forcing the user to figure out what the path is & enter it him/herself? The shell seems to parse pretty well, so is this a case of legacy issues? Performance issues? What?

9
  • 5
    You statement "the ln command creates a symlink, with the default being a hard link and the -s option creating a soft link." should be "the ln command creates a link, the default being a hard link and the -s option creating a symbolic link".
    – jlliagre
    Apr 15, 2014 at 21:25
  • I assume you are the one that tried to edit my post? The way I see it, a symbolic link can be a soft or hard link, and what you say is a "symbolic link" is a soft link.
    – trysis
    Apr 15, 2014 at 21:30
  • 2
    @trysis The way you "see" it is non-standard usage and you are just going to confuse everyone else by insisting on using the words that way. In Unix-land, links are hard by default, and non-hard links are called symbolic. This is reflected in the naming of the system calls link(2) and symlink(2).
    – jw013
    Apr 15, 2014 at 21:37
  • Fine, I'll change it, though to be honest, I think the "standard" way is more confusing.
    – trysis
    Apr 15, 2014 at 21:39
  • @jiliagre is correct. The way you see it is wrong. Symbolic links are a subset of links. From the man page: " -s, --symbolic make symbolic links instead of hard links". Additionally symlinks do not have to contain the whole path. touch a; ln a b -s; ln ./a c -s; ln $PWD/a d -s
    – Pete
    Apr 15, 2014 at 21:40

3 Answers 3

6

Read your man page: Question 1 = 1st Form, this is because in linux all items are considered files, even directories. As an example, use your text editor to "open" /etc/, ie: nano -w /etc/ nano will politely tell you /etc/ is a directory Since it's technically legal to create never ending symlinks. In the old days, before the bounds check was written, I could have an FHS system with 2 files named /etc, one being a file and one being a directory, and the system knew the difference

(See the haha note in the chromiumos developer guide:

There is a file system loop because inside ~/trunk you will find the chroot again. Don't think about this for too long. If you try to use du -s ${HOME}/chromiumos/chroot/home you might get a message about a corrupted file system. This is nothing to worry about, and just means that your computer doesn't understand this loop either. (If you can understand this loop, try something harder.

I Dare you, click on something harder :) In order to prevent the looping ln requires the full path.

Question 2 can be answered by reading the man page again Look at the last sentence:

DESCRIPTION

   In the 1st form, create a link to TARGET with the name LINK_NAME.  In
   the 2nd form, create a link to TARGET in the current directory.  In
   the 3rd and 4th forms, create links to each TARGET in DIRECTORY.
   Create hard links by default, symbolic links with --symbolic.  By
   default, each destination (name of new link) should not already
   exist.  When creating hard links, each TARGET must exist.  Symbolic
   links can hold arbitrary text; if later resolved, a relative link is
   interpreted in relation to its parent directory.

Re: Edit: "However, why can't the shell parse out that path when you're running the command, rather than forcing the user to figure out what the path is & enter it him/herself?"


Consider this example: Application A installs Library version 1.0.a. You build applications X,Y,Z that depend on Library A. Application A finds a bug, updates it and saves the library as 1.0.1.2.a. Since Applications X,Y,and Z still use library 1.0 if i replace 1.0 directly w/ 1.0.1.2, I'll get breakage, but if I symbolically link version 1.0.1.2 to version 1.0, nothing breaks,

ln -s /usr/lib64/libfoo-1.0.1.2.a /usr/lib64/libfoo-1.0.a

and applications X,Y, and Z get the new bugfix from the library applied to them too, because the shell follows the link from 1.0 to 1.0.1.2 but calls it 1.0. In cases like this you don't want the shell assuming the path as you increase the chance for system-wide breakage. BTW on 64-bit systems /usr/lib is linked to /usr/lib64, to remedy the example I just gave on a large scale, ie 32 bit applications expect libraries to be installed at /usr/lib, and on a 64 bit system there are no pure 32 bit libraries so /usr/lib is linked to /usr/lib64 like so:

ln -s /usr/lib64 /usr/lib
6
  • Can you give an example of the whole "symbolic links can hold arbitrary text" and how they can be resolved? I'm trying to wrap my head around that. Does this mean a symlink can be to something that isn't a file or a folder (or another link)?
    – trysis
    Apr 15, 2014 at 21:56
  • ln -s /etc/hosts ~/this_is_my_hosts_file In this case, this_is_my_hosts_file is the arbitrary texts. The system resolves properly because the link is a pointer. ln resolves poinnter to pointer to pointer to file, which allows a ln to an ln to an ln to a file, just as long as the ln isn't circular.
    – eyoung100
    Apr 15, 2014 at 22:00
  • I'm going to ignore that bad grammar, as I could mostly make out what you said. You used an example where the target file is already there, and is a file. Your quote makes it seem like the target file could be anything (bearing in mind that everything in Linux is a file), and doesn't have to be there at the moment.
    – trysis
    Apr 15, 2014 at 22:17
  • @trysis in this context, a file can be a file or a directory, and that quote is not my bad grammar... That quote was taken directly from the ln manpage :)
    – eyoung100
    Apr 15, 2014 at 22:21
  • I was referring to your comment, although now that I look at it, I suppose there isn't as much bad grammar as I thought. I was mistaking the ln (lowercase L) in "ln resolves poinnter to pointer to pointer to file" for "In" (uppercase i) as they're so similar.
    – trysis
    Apr 15, 2014 at 22:34
2

Question 1: Why does the whole path need to be written out for both files/folders for a soft link, while for a hard link we can leave out the filename for the target file?

You don't need to specify the path or the filename for the soft link too, unless the target is in the current directory. For example, if you have a file ~/Downloads/target_file, you can do:

ln `~/Downloads/target_file`

when you are in ~/, which will create a hard link to ~/Downloads/target_file in ~/ with the filename target_file and you can also do

ln -s `~/Downloads/target_file`

when you are in ~/, which will create a soft link to ~/Downloads/target_file in ~/ with the filename target_file.

Question 2: Why is the file path for the OLD file/folder of a soft link relative to its parent, while the other 3 paths (hard link OLD, NEW files, soft link NEW file/folder) are relative to the files/folders themselves?

All four paths can be relative(to the current folder) as well as absolute; the only criteria is the hard or the soft link should not be in the same folder if you are not specifying the name or path.

You should read the manual page of ln. Have tried all this on Ubuntu 14.04 but never the less have confirmed with the manual page so you don't need to worry about the OS; it isn't OS-specific.

8
  • For my Question 1, I meant when you are creating the link in another directory, not the current one. Although your insight makes links even more inconsistent. Also, it isn't technically relevant, as I'm using the form ln [-s] target link, while yours is more the form ln [-s] target.
    – trysis
    Apr 15, 2014 at 21:46
  • @trysis: I deliberately left out the link, since it is absolutely not necessary to specify that for both hard as well as soft links. Also you can still leave out the filename for both the hard and soft links.
    – jobin
    Apr 15, 2014 at 21:54
  • You're right. Wow, I could have sworn it wasn't letting me before.
    – trysis
    Apr 15, 2014 at 22:01
  • @trysis: Feel free to upvote/accept! :D
    – jobin
    Apr 15, 2014 at 22:05
  • I've been staring at the computer too long. Your second-to-last statement is mostly correct, except that the symlink behaves weirdly in this respect. Also, I figured the issue wasn't OS-specific, but said that just in case, as I can not test on all the hundreds of Linux/UNIX computers, even if I could afford them.
    – trysis
    Apr 15, 2014 at 22:12
2

When you create a hard link, the source path is used at the link creation time, so it must be a path relative to the current working directory (or an absolute path). When you create a symbolic link, the source path is treated as a string; it will be interpreted when the link is used, so it is relative to the directory where the link is.

Considering your example, where the current directory is /home/user.

  • The command ln -s new/file new2/file creates a symbolic link whose text is new/file and puts this link at the location new2/file. When a program accesses that link, the target is /home/user/new2/new/file which doesn't exist.
  • The command ln -s ../new/file new2/file creates a symbolic link whose text is ../new/file and puts this link at the location new2/file. When a program accesses that link, the target is /home/user/new2/../new/file which shortens to /home/user/new/file.
  • The command ln new/file new2/file creates a directory entry at the location new2/file which points to the same file as /home/user/new/file (which must exist).

It's often less confusing to change to the target directory before creating symbolic links.

cd new2
ln -s ../new/file .
6
  • For your second bullet point, why does the user have to enter that path? Why can't the shell figure out the path, starting from the current working directory? Is this for legacy reasons?
    – trysis
    Apr 16, 2014 at 1:45
  • 1
    @trysis What do you mean “figure out the path”? You can put whatever you like in a symbolic link. It's just a string. It doesn't need to be valid now, for example you can have a symlink that points into a removable device that isn't currently mounted. A symlink is like having a piece of paper on the door that reads “go to number 581 on Fourth Avenue” (absolute symlink) or “go south 3 blocks and knock at the third door” (relative symlink); you can write that piece of paper whether the house at this address exists or not. Apr 16, 2014 at 1:47
  • If the link is at ~/new/cd/floppy/dropbox and the target is at ~/new2/regular/folder/gdrive/dvd then, no matter what all those folders are, the shell will always have to follow ../../../new2/regular/folder/gdrive/dvd to get from the link to the target. Why should the user have to write that monstrosity into the shell instead of entering the simpler new2/regular/folder/gdrive/dvd and letting the shell figure out where that is?
    – trysis
    Apr 16, 2014 at 2:02
  • @trysis The target of a symbolic link is a string, not a path. It's interpreted as a path (relative to the directory where the symlink is) when the link is traversed. If the target is /home/user/new2/regular/folder/gdrive/dvd, that's an absolute path. If the target is new2/regular/folder/gdrive/dvd, then that corresponds to new2` being a subdirectory of /home/user/cd/floppy. Apr 16, 2014 at 2:07
  • 1
    @trysis, the answer to your last comment is the very first paragraph of this answer.
    – Wildcard
    Sep 7, 2017 at 3:53

You must log in to answer this question.

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