Hard Link Vs Symbolic Link 101

August 25, 2021

You probably have heard of "hard link" (ln) and "symbolic link" (ln -s). You may have some vague idea that these commands have something to do with linking a file to another file... or something like that. This article will clarify the differences between ln and ln -s and provide some use cases.

To get the most out of this, I strongly encourage you to code along as you read. Meaningful reading is not passive. It is an active act where you, the reader, must also put in the work to get the most out of this article.

As much as you can, do lots of experiments on your own: try different variations of a command, repeat the command without looking at the article, and repeat it again the next day to fortify your memory (you'll be surprised at how fast you forget things!).

Hard Link

If you have Googled "hard vs soft link" in the past, you might have seen a reference to an "inode". An inode is a file's unique serial number. When you create a new file (touch newfile.txt), you are actually creating an inode and a link to that inode. That file that you just created consists of at least two parts: an inode (a unique identifier) and a file name.

Let's create a file, test1.txt. Inside it, add some texts:

touch 'hello test1' >> test1.txt

Aight, you created a file. Now let's create a hard link - let's call it hard1.txt. Remember - when you create a new hard link, you are creating a new link to the inode of the original file.

ln test1.txt hard1.txt

Now run ls -l. You should see two files displayed: a test1.txt and a hard1.txt. If you run cat hard1.txt, you'll see that it has the same content as test1.txt.

Next, add a line into test1.txt:

echo "Hello again test1" >> test1.txt

You'll see "Hello again test1" inside both test1.txt and hard1.txt. Changing the original file changes the hard link file as well!

What if we change the content of hard1.txt instead? Let's find out!

echo "Hello from hard1" >> hard1.txt

You should see "Hello from hard1" text inside both hard1.txt and text1.txt. So changing either the original or the hard link file changes the other.

Finally, let's see what happens if we delete the original file, test1.txt.

rm test1.txt

Notice that hard1.txt is still there and the text inside hasn't changed. Great!

Let's recap. When you created test1.txt, you created an inode. It contained "hello test1" initially. This inode (I'll call it "test1 inode") is connected to a file name test1.txt. When you ran ln test1.txt hard1.txt, you created a new file name, hard1.txt, connected to the test1 inode. Think of test1 inode like an underground rabbit's burrow. test1.txt and hard1.txt are the two holes connecting that burrow to the surface. From the outside, we see two holes. If you remove one hole, the bunny can still go out from the other hole. If you create a new hard link, you are just creating a third hole to the same, existing burrow. If you delete the test1.txt burrow, it won't affect hard1.txt at all! The only way to remove it is to completely remove all references to the inode. You need to remove all the hard links.

A few things that I'd like you to do:

  1. We've deleted test1.txt but we still have hard1.txt. Create another hard link out of hard1.txt, name it anotherhard1.txt. What do you expect to happen? What does this tell you about the rm command? (It doesn't really "delete" the file. It actually deletes a link to an inode)
  2. Rename hard1.txt to another name, hardy1.txt. What is the relationship between anotherhard1.txt and hardy1.txt?
  3. Modify the content of one of the hard links. What do you think will happen to the content of the rest of the links?
  4. When do you think a hard link might come in handy? What is the use case?
  5. By the way, if you want to see the inode of a file, you can use ls -i hard1.txt. Compare the inode number of a file vs its hard link and the inode number of a file vs its symlink (do this one later after you read the symlink section). You will find that the hard link has the same inode number as the original link and that a symlink has a different inode number as the original link.

Don't go to the next section yet. Spend some time creating your own hard links. Modify them. Do things that weren't covered in this section.

Unlike a hard link that points a file to an inode, a symbolic link (sometimes known as a soft link) connects by a file name, not an inode. Because it doesn't connect to an inode like that underground rabbit burrow analogy and it only connects on the surface level, their connection is "softer / weaker" than hard links (that's how I think about it anyway). As a result, by simply changing the name of the original file, you destroy its connection.

Create a new file test2.txt and add a line into it:

echo "hello test2" >> test2.txt

Now create a symlink:

ln -s test2.txt soft2.txt

If you check the content inside test2.txt and soft2.txt, you'll notice that they are one and the same. Good.

Let's update the content:

echo "hello soft2" >> soft2.txt
cat soft2.txt
cat test2.txt

echo "hello original" >> test2.txt
cat soft2.txt
cat test2.txt

Notice that updating either the symlink file or the original file updates the other file. So far symlink acts like a hard link.

Now here comes the kicker. If you either change the name of the original file or remove the original file (rm test2.txt), it will break the connection.

rm test2.txt

cat soft2.txt
cat: soft2.txt: No such file or directory

Retrospectively, if you had renamed the original file:

mv test2.txt somethingelse2.txt

cat soft2.txt
cat: soft2.txt: No such file or directory

However, if you instead had removed the symlink file instead and kept the original file, the content of the original file is preserved.

rm soft2.txt

cat test2.txt
# content is still there

Spend some time to play around with symlinks. Do the things that I didn't mention in this section. Learn by breaking things.

Here are some things to think about:

  1. Can you create a soft link out of a soft link?
  2. What would happen if you move the location of the original file to a different directory (but keep the same name)?
  3. Can you create a soft link out of a hard link?
  4. Can you create a hard link out of a soft link?
  5. Create a symlink and a hard link from a file. Do different things to each. Notice how they differ.

Usage

Now that you know what the differences between ln and ln -s are, let's talk about usage.

One usage for a symbolic link is to create portable dotfiles. I use Vim as a text editor. Vim can be configured with a .vimrc file and a .vim/ directory in the root directory. But what if I want to keep my dotfiles portable and my config files source-of-truth inside ~/Projects/iggy-dotfiles/vimrc and ~/Projects/iggy-dotfiles/vim/?

Before learning about ln, I used to copy-paste the vimrc file and vim/ directory from my dotfiles into the root directory. But if I copy-paste them, anytime I make changes to ~/.vimrc, I would have to apply the same change to my ~/Projects/iggy-dotfiles/vimrc file (I can also use rsync, but that still requires a manual syncing). That's not good. I want to change either ~/.vimrc or ~/Projects/iggy-dotfiles/vimrc and have the other file to update automatically - wait a second... this sounds like symlink!

A better way is to run:

rm ~/.vimrc
ln -s ~/Projects/iggy-dotfiles/vimrc ~/.vimrc

With this, each time I make changes to either dotfiles vimrc or root vimrc, the content will always be the same. Btw, you can also use a symlink on a directory, so ln -s ~/Projects/iggy-dotfiles/vim/ ~/.vim should work.

By the way, you could've also used a hard link, but the popular convention is to use symlink. If I ever need to delete a file, I can just delete ~/Projects/iggy-dotfiles/vimrc and my ~/.vimrc will automatically become obsolete. Having only one source of truth makes it easier to keep track of where things are. If you used a hard link, you'll have to remember to delete all of your vimrc sources.

You can use this technique with any config files like .zshrc, .bashrc, .launch.json, etc.

On the other hand, hard links are useful for backups. For example, if you have a directory full of books:

aesop_fables.pdf
bradbury_fahrenheit.pdf
calvin_institutes.pdf
darwin_origin.pdf
...

Assume that you need to create multiple directories so you can sort them based on author and title. It doesn't make sense to copy all your books into the directory authors/ and once more in title/. It makes more sense if you keep the original books, then create a hard link twice (remember, creating a hard link barely takes up any space). Inside the authors/ directory you can have your books named and sorted by author. Inside the title/ directory you can name and sort them by title. You can "duplicate" and "sort" your data as many ways as you want and they will barely take up any space.

We've reached the end. Thanks for making it this far. Hopefully by now you've understood ln vs ln -s and put this knowledge to good use. Keep learning and happy coding!