Linux & Bash · Part I · Module 6 · Links and File Identity
Symbolic Links and the Ways They Break
The second kind of link works on a completely different principle from the first, and the difference is worth stating before anything else. A hard link is a name — an entry pointing straight at an inode. A symbolic link is a file in its own right, with its own inode, whose entire contents are a path written out as ordinary text. Nothing is connected to anything; a piece of text is stored, and looked up afresh every single time the link is used. That is a weaker arrangement than a hard link in every respect, and it is also far more useful, because almost everything a hard link refuses to do becomes possible once the connection is just some text.
Intermediate17 min readLinuxPart IFundamentalsFilesystemLinks
Part I · Module 6 · Chapter 6.3 · Symbolic Links and the Ways They Break
1. A File Containing a Path
$ ln -s rtl/top.v top_link.v
$ ls -li rtl/top.v top_link.v
83084083 -rw-r--r-- 1 engineer engineer 22 Mar 28 12:49 rtl/top.v
83084084 lrwxr-xr-x 1 engineer engineer 9 Mar 28 12:49 top_link.v -> rtl/top.vCompare that with Chapter 6.2's output, where the two names shared an inode. Here everything differs:
- different inode numbers —
83084083and83084084. Two separate files. - the type character is
l, not-. Chapter 2.5 listed it and deferred it; this is it. - the link count on each is 1. Neither is a second name for the other.
ls -lshows an arrow naming what the link points at.- the size is 9, and
rtl/top.vis nine characters long.
That last one is the whole model made concrete. The size of a symbolic link is the number of characters in the path it stores, because that path is its contents.
$ ln -s rtl current
$ ls -l current
lrwxr-xr-x 1 engineer engineer 3 Mar 28 12:49 current -> rtlThree characters, three bytes. It is a tiny file whose contents are the text rtl.
2. Using One
Most of the time a symbolic link behaves as though it were the thing it names. Programs that open it get the target, because the system follows the link automatically:
$ cat top_link.v
module top;
endmodulecat asked for top_link.v; the system read the stored path, went to rtl/top.v, and opened that. This is called following the link, and it happens by default almost everywhere.
The form of the command mirrors ln from Chapter 6.2, with -s for symbolic:
ln -s TARGET LINK_NAMEThe order catches people. The thing being pointed at comes first; the new link comes second — the same shape as cp and ln. Reversing it either fails or creates a link with the wrong name pointing at the wrong place.
3. What It Can Do That a Hard Link Cannot
All three of Chapter 6.2's restrictions disappear, and for one reason: a path is just text, and text has none of an inode number's limitations.
It can point at a directory:
$ ln -s rtl current
$ ls current
top.v
$ cd currentThis is the most common use by far. A stable name — current — that can be repointed at whichever directory is current this week, without moving anything.
It can cross filesystems:
$ ln -s /other_disk/big_data data_linkChapter 2.1 explained that one tree spans many filesystems. A stored path can name any location in the tree, so there is nothing to refuse.
It can point at something that does not exist:
$ ln -s /not/here/yet placeholderNo error. Nothing checked, because nothing was connected — a piece of text was written down. Which is §4's subject.
4. The First Failure: a Dangling Link
$ printf 'temp\n' > tmp.txt
$ ln -s tmp.txt ghost
$ cat ghost
temp
$ rm tmp.txt
$ ls -l ghost
lrwxr-xr-x 1 engineer engineer 7 Mar 28 13:02 ghost -> tmp.txt
$ cat ghost
cat: ghost: No such file or directoryRead that carefully, because the two outputs appear to contradict each other.
ls -l ghost succeeded. The link is right there, with its arrow, its size and its date. Nothing about the listing suggests a problem.
cat ghost says the file does not exist. Also true — cat followed the stored path to tmp.txt, which has been removed.
Both are correct, because they are talking about different things. The link exists. What it points at does not. A link in this state is called dangling, or broken.
Nothing warned you when tmp.txt was deleted, and nothing could have: the target has no idea the link exists. Chapter 6.2's link count only counts hard links, so removing a file with symlinks pointing at it is indistinguishable from removing any other file.
Telling a dangling link from a missing file
Two tests distinguish them, and the pair is the precise diagnostic:
$ [ -e ghost ] && echo "target exists" || echo "target does NOT exist"
target does NOT exist
$ [ -L ghost ] && echo "it IS a link"
it IS a link-easks "does this resolve to something?" — it follows the link, so a dangling link fails the test.-Lasks "is this a symbolic link?" — it does not follow, so it succeeds even when dangling.
A path where -L succeeds and -e fails is exactly a dangling link. (The [ ... ] syntax is a test expression and belongs to Chapter 16.4, which measures the whole matrix of file tests against a dangling link; it is shown here because it is the clearest way to express the distinction.)
Many systems also colour dangling links differently in ls output — useful, and per Chapter 2.4 not something to rely on.
5. The Second Failure: a Relative Link That Moved
This one is subtler and catches people who understand §4 perfectly well.
A link can store either kind of path from Chapter 2.2:
$ ln -s /home/engineer/project/rtl/top.v abs_link.v # absolute
$ ln -s ../rtl/top.v rel_link.v # relativeA relative path in a link is resolved from the directory the link is in — not from your working directory, and not from wherever it was created.
Watch it work, then break:
$ cd /home/engineer/project/sim
$ ln -s ../rtl/top.v here_link.v
$ ls -l here_link.v
lrwxr-xr-x 1 engineer engineer 12 Mar 28 13:15 here_link.v -> ../rtl/top.v
$ cat here_link.v
module top;Correct. The link sits in sim, so ../rtl/top.v resolves to project/rtl/top.v.
Now move the link — not the target — one level up:
$ mv here_link.v ../moved_link.v
$ cd ..
$ ls -l moved_link.v
lrwxr-xr-x 1 engineer engineer 12 Mar 28 13:16 moved_link.v -> ../rtl/top.v
$ cat moved_link.v
cat: moved_link.v: No such file or directoryThe stored text is identical — still ../rtl/top.v, as the listing shows. The link now lives in project, so that text resolves to /home/rtl/top.v, which does not exist.
Nothing was corrupted. Chapter 2.2's rule simply applied from a new starting point, exactly as it would for a relative path you typed. The link's meaning depends on where the link is, and the link moved.
6. Seeing the Link Rather Than Its Target
Because most commands follow links silently, you sometimes need to insist on seeing the link itself.
$ ls -l current
lrwxr-xr-x 1 engineer engineer 3 Mar 28 12:49 current -> rtl
$ ls -lL current
total 8
-rw-r--r-- 1 engineer engineer 22 Mar 28 12:49 top.vls -l described the link. ls -lL followed it and described the target — here a directory, so its contents were listed.
This is the general pattern, and it recurs across many commands: an uppercase -L means follow symbolic links, and a -P means do not — Chapter 6.4 is about that pair. Two cases worth knowing now:
$ rm current # removes the LINK, never the target
$ cp -r current/ x/ # follows by default — copies the target's contentsrm on a symlink is safe in a way that often surprises people: it removes the small text file and leaves whatever it pointed at completely untouched.
7. Replacing Where a Link Points
The common maintenance operation on the current pattern:
$ ls -l current
lrwxr-xr-x 1 engineer engineer 10 Mar 28 13:30 current -> release_v2
$ ln -sf release_v3 current
$ ls -l current
lrwxr-xr-x 1 engineer engineer 10 Mar 28 13:31 current -> release_v3-f is force: replace an existing link rather than refusing. Without it, ln -s declines because the name is taken.
One trap here is worth stating, because it is the most common way people make a mess with symlinks:
$ ln -sf release_v3 current/With a trailing slash — or when current already points at a directory and you omit -n on some systems — you can end up creating a link inside the target directory instead of replacing the link. The result is release_v2/release_v3, and current still points at the old place.
Check afterwards, always:
$ ls -l current8. Why They Are Everywhere
Symbolic links are far more common than hard links, and three patterns account for most of what you will see.
A stable name for a moving target. current -> release_v3. Everything refers to current, and switching version is one command that moves no data. This is the dominant pattern in engineering environments.
A short name for a long path. A link in your home directory pointing at a project area six levels deep in a shared filesystem.
A tool reachable under several names. Chapter 6.1's example of several paths leading to one program is often implemented with symlinks rather than hard links, which is why ls -l on something in a bin directory frequently shows an arrow.
All three rely on the property that makes symlinks weaker than hard links — the connection is text, resolved later — and all three need that property, because all three involve pointing at something that may change.
9. Why This Matters in Engineering Work
Version switching without copying. The current pattern is how large shared tool and release areas work. Repointing one link switches everybody to a new version; the old one stays in place and can be switched back instantly.
Broken links after a copy or an archive. Chapter 3.2's cp -r and Chapter 3.6's tar both have choices about whether to copy links or what they point at. A tree that "copied fine" and then fails at run time with missing files is very often links that came across as links, pointing at paths that mean something different in the new location. §5's relative-or-absolute question is what decides whether that happens.
Diagnosing "the file is there but the tool cannot read it". A dangling link looks present in every listing and absent to every program. §4's -L and -e pair settles it in one line.
Part II works in exactly these environments, and the current-style link is assumed throughout.
10. Practice
Question 1. Give the one-sentence definition of a hard link and of a symbolic link, and say which one is a file in its own right.
Question 2. ls -l shows a symlink with a size of 12. What determines that number?
Question 3. Name three things a symbolic link can do that a hard link cannot, and the single property that allows all three.
Question 4. ls -l ghost succeeds but cat ghost reports no such file. Explain how both can be true, and name the condition.
Question 5. Which two tests distinguish a dangling link from a path that does not exist at all? What does each one do about following?
Question 6. A link in sim/ stores ../rtl/top.v and works. You move the link to the parent directory. Give the path it now resolves to and explain why, referring to Chapter 2.2.
Question 7. You are linking to something inside the same project tree, which will later be archived and extracted elsewhere. Relative or absolute? Explain.
Question 8. What is the difference between rm current and rm -r current/ when current points at a directory?
Question 9. ls -l current and ls -lL current give different output. What does each describe?
Question 10. A tree was copied to a new machine and several tools now report missing files, though everything appears to be present. Give the most likely cause and the command you would run first.
11. Remember
- A symbolic link is a file whose contents are a path written as text, resolved freshly every time it is used. A hard link is a second name for one inode.
ls -lshows typeland an arrow, and its size is the length of the stored path.- It has its own inode and a link count of 1. It is not the target under another name.
ln -s TARGET LINKNAME— target first, likecp.- Because the connection is text, it can point at a directory, cross filesystems, and point at something that does not exist.
- A dangling link is one whose target is gone. The listing succeeds and reading fails;
-Lsucceeds while-efails. - A relative link resolves from the directory the link is in. Move the link and its meaning changes, even though the stored text does not.
- Relative for targets inside the same tree; absolute for targets outside it. That one question prevents both failure modes.
-Lfollows,-Pdoes not — a pair you will meet across many commands, and Chapter 6.4's subject.rm linkremoves the link;rm -r link/removes the target's contents. The trailing slash is the whole difference.ln -sfrepoints an existing link, and you should check the result afterwards.
One chapter remains. Both kinds of link are now in place, which raises a question with two different correct answers: when a path goes through a link, where does it actually lead — and which answer does the command in front of you use?
Where this fits
Part of the Linux & Bash curriculum.
