When writing shell scripts or working with file paths in the Linux terminal, you frequently need to extract just the filename from a full path, or conversely, extract just the directory portion without the filename. Doing this manually with string manipulation is error-prone and unnecessarily complex.
Linux provides two dedicated commands for this exact purpose: basename and dirname. These small, focused utilities cleanly separate a file path into its component parts, making them indispensable for robust, portable shell scripting.
Using the basename Command
The basename command strips the directory path from a full file path and returns only the final component—typically the filename.
Basic Usage
Pass a full file path as an argument:
basename /home/johndoe/documents/report.pdf
Output: report.pdf
Everything before and including the last forward slash is removed. Only the final filename (or directory name, if the path points to a directory) is returned.
Removing File Extensions
A particularly useful feature of basename is its ability to strip a specified file extension from the result. This is invaluable when writing scripts that process files and need to create output files with a different extension.
To remove the .pdf extension from the filename, pass the extension as a second argument:
basename /home/johndoe/documents/report.pdf .pdf
Output: report
This cleanly returns just the base name of the file without the extension. You can then use this in a script to, for example, create a corresponding .txt file with the same name.
Using basename in a Shell Script
A common pattern in bash scripts is to capture the output of basename in a variable using command substitution:
FILENAME=$(basename "$FILEPATH" .csv)
If $FILEPATH contains /data/exports/sales_2026.csv, the variable $FILENAME will hold the value sales_2026. You can then use this variable to create new output files dynamically:
mv "$FILEPATH" "/archive/${FILENAME}_archived.csv"
Using the dirname Command
The dirname command performs the opposite operation to basename. It strips the final component (the filename) from a path and returns everything that precedes it—the directory portion.
Basic Usage
dirname /home/johndoe/documents/report.pdf
Output: /home/johndoe/documents
The filename (report.pdf) is removed, and only the parent directory path is returned.
Handling Edge Cases
The dirname command handles several edge cases gracefully:
- If you pass just a filename with no directory path (e.g.,
dirname report.pdf), it returns.(a single dot), representing the current working directory. - If you pass the root path (e.g.,
dirname /), it returns/. - Trailing slashes on directory paths are handled correctly:
dirname /home/johndoe/returns/home.
Using dirname in a Shell Script
A common use case for dirname is to determine the directory a script is located in, regardless of where it was called from. This is essential for scripts that need to reference other files relative to their own location.
SCRIPT_DIR=$(dirname "$0")
The special variable $0 contains the path used to invoke the current script. Wrapping it in dirname extracts just the directory, allowing you to build reliable relative paths like "$SCRIPT_DIR/config.ini".
Combining basename and dirname
You can use both commands together in a single pipeline to perform complex path manipulation.
For example, to extract the immediate parent directory name (not the full path) of a file:
basename $(dirname /var/log/nginx/access.log)
Output: nginx
This first extracts /var/log/nginx using dirname, and then extracts nginx from that path using basename. This technique is useful for organising log files or grouping outputs by their parent directory name.
By incorporating basename and dirname into your Linux toolkit, you can write cleaner, more portable shell scripts that handle file paths reliably across different directory structures.