Learn › Linux Foundations › Manipulation
readlink - a hands-on Linux lab on a real virtual machine.
Read where a symbolic link points with readlink. Plain readlink prints the raw target stored in the link; readlink -f canonicalizes, following every link and resolving .. to one absolute path, with -e and -m as its stricter and looser cousins. On a regular file readlink prints nothing and exits 1, which is the most common surprise. The read half of the ln -s pair.
You are standing in front of a signpost. It clearly points somewhere, but the label is turned away from you. You can see the arrow. You cannot read the destination.
A symbolic link is that signpost. It is a tiny file whose only job is to point at another file somewhere else on the disk. Its name is a signpost you can see with ls, but ls will not tell you where it aims. This lesson is about the one command that reads the writing on the signpost and tells you exactly where the arrow points. It is called readlink.
The black boxes in this lesson are a practice terminal: a safe sandbox that only checks the one command each step teaches, so you cannot break anything. Every output shown here is fixed by the tiny scene you build in the next step, not by any particular machine, so what you see below is exactly what the real machine prints too.
readlink reads one thing: the target stored inside a symbolic link. The target is the path the link points at. When you make a link, that path is written inside it, and readlink prints it back, nothing more.
Remember ln -s from the last lesson. ln -s <target> <linkname> builds a symbolic link. readlink is the other half of that pair: ln -s writes the arrow, readlink reads it. One makes the signpost, the other tells you where it points.
You need a signpost before you can read one. Build the tiny scene now. First a real file, then a link that points at it:
ln -s /home/student/original.txt shortcut
prompt: student@linuxcamp:~$ answer: ln -s /home/student/original.txt shortcut output: hint: Type ln, a space, -s, the full target path, a space, then the link name shortcut: ln -s /home/student/original.txt shortcut
Nothing printed, and that is success. ln -s is silent when it works, just like the copy and move commands you met earlier. You now have a file called shortcut sitting in your home folder, and inside it is a single path: /home/student/original.txt. That path is the target. In the next step you read it back out.
Before you read the arrow, prove there is an arrow to read. The -l flag on ls, the long listing you learned earlier, marks a symbolic link in an unmistakable way. The line starts with the letter l (for link), and it draws the arrow for you with ->.
List the link in long form and look at the two clues:
ls -l shortcut
prompt: student@linuxcamp:~$ answer: ls -l shortcut output: lrwxrwxrwx 1 student student 26 Jul 5 12:00 shortcut -> /home/student/original.txt hint: Reuse ls with the -l flag, then the link name: ls -l shortcut
Two things mark this as a link. The very first character on the line is l, not the - you would see for a regular file. And near the end, ls -l prints shortcut -> /home/student/original.txt, drawing the arrow and its destination right there. That -> is the target ls read out of the link for you. readlink prints the same destination, but on its own, with none of the extra columns. That clean single line is what you want next.
Now read the signpost. Hand readlink the name of the link and it prints one line: the target path stored inside, and nothing else. No permissions, no date, no arrow drawing. Just the destination.
Before you run it, decide what you expect. You wrote /home/student/original.txt into the link a moment ago, so that is exactly what should come back. Confirm it:
readlink shortcut
prompt: student@linuxcamp:~$ answer: readlink shortcut output: /home/student/original.txt hint: Type readlink, a space, then the link name shortcut: readlink shortcut
There is the target, printed clean on one line: /home/student/original.txt. That is the whole promise of readlink. It reached inside the link, found the path stored there, and printed it with none of the clutter ls -l adds. This is the form you reach for in a script, when you need the destination as plain text you can feed to another command. Whatever path you wrote with ln -s is exactly what readlink reads back.
Here is the trap that catches everyone once. readlink only reads links. Give it a normal file, one that is not a signpost at all, and it has nothing to read. So it prints nothing and quietly reports failure.
You met the exit code in earlier lessons. It is the number a command hands back when it finishes: 0 means success, anything else means failure, and you read it with echo $?. Because readlink is silent on a regular file, that exit code is the only proof of what happened. Point it at the real file original.txt and reveal the code on the same line:
readlink original.txt; echo $?
prompt: student@linuxcamp:~$ answer: readlink original.txt; echo $? output: 1 hint: Type readlink, the regular file name, a semicolon, then echo $?: readlink original.txt; echo $?
Look closely: the only thing printed is 1. readlink itself said nothing, because original.txt is a regular file, not a link, so there was no arrow to read. The 1 came from echo $?, and 1 means failure. This is the single most common surprise with readlink: silence plus a 1 does not mean the file is missing, it means the file is not a symbolic link. When a script calls readlink and gets an empty answer, this is almost always why.
Plain readlink prints exactly what is written in the link, no more. But links can point at links, and paths can contain .. for parent folder, so the raw target is not always the real final location. The -f flag fixes that. -f stands for canonicalize: it follows every link in the chain and resolves every .., then prints the one true absolute path at the end.
This is the form you will type most often. On your simple link the answer matches the plain target, which makes it easy to trust. Run it:
readlink -f shortcut
prompt: student@linuxcamp:~$ answer: readlink -f shortcut output: /home/student/original.txt hint: Add the -f flag between readlink and the link name: readlink -f shortcut
Same clean path, /home/student/original.txt, because your link points straight at a real file with no chain and no .. to untangle. That is the point of practicing -f on a simple case first: you can see it agrees with plain readlink here, so you trust it later when the path is tangled. On a messier setup, a link to a link to a file, -f would quietly walk the whole chain and still hand you one final absolute path. That is why readlink -f is the form engineers reach for when they need the real, resolved location of something.
-f has two close relatives, and the only difference between the three is how strict they are about whether the path really exists on disk. Learn them as a family:
All three canonicalize the same way. Use -f for everyday work, -e when you want a hard check that the target is really there, and -m when you are building a path that does not exist yet. Confirm -e agrees with -f here, because your target original.txt does exist:
readlink -e shortcut
prompt: student@linuxcamp:~$ answer: readlink -e shortcut output: /home/student/original.txt hint: Swap the -f flag for -e, keeping the same link name: readlink -e shortcut
Same path again, /home/student/original.txt, because -e only differs from -f when the target is MISSING. Here original.txt really exists, so -e is happy and prints the resolved path. Had the link pointed at something absent, -e would have printed nothing and failed. In that same case, -f would still print the path and -m would never complain. Same canonical answer, three levels of fussiness about reality.
Scaffolding off. No command is printed this time. You have every piece you need.
Someone hands you a symbolic link named shortcut and asks a plain question: exactly what path is written inside it? Not the resolved, canonicalized version, just the raw target as it was stored. Print that single line.
prompt: student@linuxcamp:~$ answer: readlink shortcut output: /home/student/original.txt hint: The raw target means no flag at all. Think readlink, then the link name.
That is the everyday move. Plain readlink with no flag prints the target exactly as it is stored inside the link, /home/student/original.txt, with no clutter and no resolving. You chose the bare form on purpose, because the question asked for the raw arrow, not the canonical destination that -f would give. Reading a link's target from memory, no scaffold, is the same recall the real machine will ask of you.
Two things go wrong near readlink, and neither prints a loud error, which is what makes them confusing. Here is each one, what it means, and what to check first:
An empty result with exit code 1 almost always means the thing you named is not a symbolic link. Check with ls -l: a link's line starts with l and shows an -> arrow. A regular file starts with - and has no arrow, so readlink has nothing to read.
The message readlink: missing operand means you typed readlink with no name after it. readlink needs to be told which link to read. Check that you gave it a name: readlink shortcut, not a bare readlink.
When you are not sure whether a name is a link, ls -l is the fast first look and readlink is the clean follow-up. ls -l shows you the arrow with all its columns; readlink gives you just the destination, ready to hand to another command.
You earned this cheat sheet. Every row is a form you just ran:
The one idea under all of it: plain readlink reads the arrow exactly as written, and readlink -f follows the arrow all the way to the real, resolved file. When readlink prints nothing, check ls -l: you are almost certainly pointing at a regular file, not a link.
readlink and ln -s are a matched pair. ln -s writes the target into a new link; readlink reads that target back. Whenever you build a link and want to be sure it points where you meant, readlink is the one-line check.
The practice terminal has shown you the whole of readlink. Plain readlink prints the raw target of a link. readlink -f follows the arrow to the real absolute path, with -e and -m as its stricter and looser cousins. And on a regular file it stays silent and exits 1. Every one of those you typed yourself.
The Manipulation module ends with one real Linux machine, the module capstone mission, and that is where you put these pieces to work for real. A VM boots just for you, with a live shell and real links to read. It hands you objectives that use exactly what you practiced across this module: making files, copying, moving, linking, and now reading where a link points. One difference from here: the mission shows no commands. You read the objective, you recall the command, you type it. That recall is what makes it stick.
Finish the other Manipulation lessons, then go read a real signpost for yourself.
Practice readlink in a real Linux terminal at The Linux Camp. Progress is verified automatically as you type commands on the machine.