Learn › Linux Foundations › Manipulation
dirname - a hands-on Linux lab on a real virtual machine.
Meet dirname, the mirror of basename: it keeps the folder part of a path and drops the final name. dirname /home/student/report.txt prints /home/student. A trailing slash is ignored first, a bare name gives a single dot for the current directory, and root gives itself. It reads only the path text, never the disk, so the answer is the same on every machine. Pair it with basename to split any path into folder and file.
Here is a full path: /home/student/report.txt. Your eye reads it as one thing, a file. But it is really two things stitched together with slashes: a folder it lives in, /home/student, and a name inside that folder, report.txt.
Now the question. A script has the whole path in hand and needs only the folder part. Not the file, just the directory that holds it. Chopping the last name off a path by hand is fiddly and easy to get wrong. There is one command whose entire job is to do exactly that, cleanly, every time, and it is called dirname.
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. dirname does pure text surgery on the path you type. It never looks at the disk, so it prints the same answer on every machine. The outputs shown here are exactly what you will see everywhere.
dirname takes a path and prints the directory part: everything up to, but not including, the final name. The name is short for directory name. Hand it /home/student/report.txt and it hands back /home/student.
The key idea is that dirname is working on the TEXT of the path, not on any real file. The file report.txt does not have to exist. The folder /home/student does not have to exist. dirname is not checking the disk; it is splitting a string at the last slash and giving you the left half. Think of it as a pair of scissors that always cuts in the same place: just before the last name.
dirname and its twin basename were standardised together in the early Unix days for one reason: shell scripts constantly need to split a path into its folder and its file. dirname keeps the folder and throws the name away. basename, from the last lesson, does the mirror image: it keeps the name and throws the folder away. Same cut, opposite halves.
Start with the plainest case, the one you will use most. Give dirname a full path to a file and watch it return just the folder that holds it.
Because dirname only ever prints a path and nothing else, you will run it on its own here so the answer sits alone on a line. Run it now:
dirname /home/student/report.txt
prompt: student@linuxcamp:~$ answer: dirname /home/student/report.txt output: /home/student hint: Type dirname, a space, then the whole path: dirname /home/student/report.txt
The final name, report.txt, is gone, and what prints is /home/student, the folder it lived in. dirname found the last slash in the path and kept everything to the left of it. Nothing was read from disk; the file did not need to exist. This is the move a script makes when it holds a file's full path but wants to work inside that file's folder. It can cd into the folder, list it, or drop a sibling file next to the original.
Here is where most people guess wrong, so slow down. What happens if the path ends in a slash, like /home/student/? You might expect dirname to hand back /home/student. It does not.
dirname treats a trailing slash as if it were not there, then drops the last name. So /home/student/ becomes /home/student in its eyes, and dropping the last name, student, leaves /home. Before you run it, fix that answer in your head: not /home/student, but /home. Now check yourself:
dirname /home/student/
prompt: student@linuxcamp:~$ answer: dirname /home/student/ output: /home hint: Include the trailing slash exactly as shown: dirname /home/student/
It printed /home, not /home/student. That surprises almost everyone the first time. The rule is simple once you see it: dirname ignores a trailing slash, so the last real name in /home/student/ is student, and dropping it leaves /home. Remember this whenever a path comes from something that adds a slash for you, because the folder you get back is one level higher than the slash makes it look.
Now the opposite corner. What if the path has no folder in it whatsoever, just a plain filename like report.txt? There is no slash to cut at, so what could the directory part possibly be?
dirname answers with a single dot: .. In Linux, . is shorthand for the current directory, the folder you are standing in right now. That is the honest answer: if a name has no folder attached, the folder it lives in is wherever you are. Run it and see the lone dot:
dirname report.txt
prompt: student@linuxcamp:~$ answer: dirname report.txt output: . hint: Just the bare filename, no slashes: dirname report.txt
A single . printed, and that is dirname telling you the truth: report.txt carries no folder, so its directory is the current one, written as .. This matters in real scripts. When a path might be a bare name, dirname never fails or prints a blank; it always hands back a usable directory, and here that directory is ., right where you are standing.
One last edge, the smallest path there is: the root of the whole filesystem, /. Root is the top of the tree, the one folder that sits above everything else. It has no name to drop and nothing above it. So what does dirname / print?
It prints / right back. Root is its own parent, the one place where going up a level lands you exactly where you started. Confirm it:
dirname /
prompt: student@linuxcamp:~$ answer: dirname / output: / hint: A single forward slash and nothing else: dirname /
You handed dirname the top of the tree and it handed the top of the tree straight back. / has nothing above it, so its directory part is itself. Together with the last three drills you now know every corner case. A normal path loses its last name, a trailing slash is ignored first, a bare name gives ., and root gives /. That is the entire behaviour of the command.
dirname has almost no flags, because it does one small job. The one worth knowing is -z. Normally dirname ends its output with a newline, the invisible character that moves the cursor to the next line. -z swaps that newline for a NUL, an invisible zero byte, instead.
You will not use -z by hand. It exists for scripts that pass many paths safely, even paths containing odd characters, to another command. For today, the thing to remember is that -z changes only the separator at the end, never the directory dirname works out. The folder it prints is identical with or without it. Run the everyday cut once more so it is fresh:
dirname /usr/local/bin
prompt: student@linuxcamp:~$ answer: dirname /usr/local/bin output: /usr/local hint: Type dirname then the path with no trailing slash: dirname /usr/local/bin
The last name bin came off and /usr/local remained, the same clean cut you saw in the first drill. That is dirname's whole personality: find the last slash, keep the left side. The -z flag would change only the invisible byte printed after /usr/local, never /usr/local itself. For the labs and for almost all real work, plain dirname with no flag is all you need.
dirname does string surgery, so it cannot fail on a missing file or a bad disk. The one real error is forgetting to give it anything to cut. Here are the two messages you are most likely to see, what each means, and what to check first.
Run dirname on its own, with no path at all, and coreutils complains:
dirname: missing operand
Try 'dirname --help' for more information.
What it means: dirname needs at least one path to work on, and you gave it none. An operand is just the thing a command acts on, here the path. Check first: did you type a path after dirname? Add one, for example dirname /home/student/report.txt.
The other message you may see is command not found:
bash: dirnme: command not found
What it means: the shell could not find a command by that name, almost always a typo. Check first: the spelling. It is dirname, seven letters, all lowercase, no space in the middle.
Here is the payoff, and the reason dirname exists. On its own it gives you half a path. Paired with basename from the last lesson, it gives you both halves, and splitting a path into its folder and its file is one of the most common things a script ever does.
dirname keeps the folder. basename keeps the file. Run them on the same path and you have taken it apart cleanly. Prove the pairing on one line, using a semicolon to run two commands in a row:
dirname /home/student/report.txt; basename /home/student/report.txt
prompt: student@linuxcamp:~$ answer: dirname /home/student/report.txt; basename /home/student/report.txt output: /home/student report.txt hint: Run dirname on the path, a semicolon, then basename on the same path.
Two lines, and between them they hold the entire original path. dirname returned the folder /home/student; basename returned the file report.txt. Join them back with a slash and you have /home/student/report.txt again. This is the everyday move: a script receives one full path, then uses dirname to know which folder to work in and basename to know which file it is dealing with.
Scaffolding off. No command is printed this time. You have every piece you need.
A script just handed you the path /etc/ssh/sshd_config and you need only the folder that holds it, printed on its own line. Not the file, just the directory. Recall the command that keeps the folder and drops the last name.
prompt: student@linuxcamp:~$ answer: dirname /etc/ssh/sshd_config output: /etc/ssh hint: This is the command that keeps the directory part of a path. Type its name, a space, then the full path.
The last name sshd_config came off and /etc/ssh remained, the folder that holds it. You recalled dirname from memory and pointed it at a path you had never seen in a drill, and it made the same clean cut it always does. That is the recall the real machine will ask of you: read the goal, name the command, type it.
You earned this cheat sheet. Every row is a form of dirname you just ran:
The one idea under all of it: dirname finds the last slash and keeps the left side. It reads only the text of the path, never the disk, so the file need not exist and the answer is the same on every machine.
Remember dirname and basename as a matched pair. dirname keeps the folder, basename keeps the file. Run both on the same path and you have split it in two: dirname /var/log/syslog gives /var/log, and basename /var/log/syslog gives syslog. Whenever a script holds one full path but needs its parts, this pair is how you take it apart.
The practice terminal has shown you the whole of dirname. It keeps the folder and drops the last name. A trailing slash is ignored first, a bare name gives ., root gives /, and -z changes only the invisible byte at the end. Paired with basename it splits any path into its two halves. 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. It hands you objectives that use exactly what you practiced across this module: creating, copying, moving, linking, and splitting paths apart. 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 split real paths on a real machine.
Practice dirname in a real Linux terminal at The Linux Camp. Progress is verified automatically as you type commands on the machine.