Introduction: One can extract filename and extension in bash shell using built-in commands or external commands. The ‘$’ character introduces parameter expansion, command substitution, or arithmetic expansion. See “How To Use Bash Parameter Substitution Like A Pro” for more info. This page shows to remove file basename without path and extension in bash using various methods.
| Tutorial details | |
|---|---|
| Difficulty level | Easy |
| Root privileges | No |
| Requirements | Linux or Unix terminal |
| Category | Linux shell scripting |
| Prerequisites | Bash |
| OS compatibility | AIX • AlmaLinux • Alpine • Arch • BSD • Debian • Fedora • FreeBSD • HP-UX • Linux • macOS • Mint • NetBSD • OpenBSD • openSUSE • Pop!_OS • RHEL • Rocky • Stream • SUSE • Ubuntu • Unix • WSL |
| Est. reading time | 5 minutes |
Bash Get Basename of Filename or Directory Name
To extract filename and extension in Bash use any one of the following method:
- basename /path/to/file.tar.gz .gz – Strip directory and suffix (extension) from filenames.
- ${VAR%pattern} – Remove file extension.
- ${VAR#pattern} – Delete from shortest front pattern.
- awk or sed – Use awk or sed text processing tool to the last part of a path (basename).
Understanding file paths in Linux
Let us take the example of the /home/vivek/foo.tar.gz file:
- /home : This is the first directory in the path. The leading / indicates that this is an absolute path, meaning it starts from the root directory of the filesystem. The path itself is a directory. A directory is nothing but a collection for other files and directories.
- /vivek : This is a subdirectory within the path directory. So, vivek is nested inside path.
- /foo.tar.gz : This is the name of a file. Let’s look at the extension or suffix:
- .tar.gz : This is a common file extension (suffix) indicating a compressed tar archive.
- .tar : This part means a “tape archive.” The tar command is used to combine multiple files and directories into a single archive file, you know like bundling things together for backups or emailing them.
- .gz : This part signifies that the .tar archive has been compressed using the gzip compression program. Gzip reduces the file size. So it will be easier to email or upload it somewhere else using the ftp.
Let us see explore example in bash to get basename of filename.
Bash get filename and extension
To just get filename from a given path. Type the following commands at the CLI:
$ FILE="/home/vivek/lighttpd.tar.gz"
$ echo "The absolute path is $FILE"
# Now print just filename from the absolute path
$ basename "$FILE"
# How about store that info into a shell variable?
$ f="$(basename -- $FILE)"
$ echo "Just filename is $f"
The basename with spaces in a bash script
Sometimes, our file names have whitespace names, and it will create problems in your scripts or commands. For example:
FILE_NAME='/home/vivek/this is a long file name .txt' echo "$FILE_NAME" # try basename now and you will get an error # basename $FILE_NAME # OR # basename -- $FILE_NAME
Outputs:
basename: missing operand Try 'basename --help' for more information.
Hence, to deal with filenames with spaces put double quote around CLI arg i.e. “$FILE” or “$FILE_NAME”. For example:
FILE="/path/to dir 1/foo.txt" f=$(basename -- "$FILE") echo "$f"
Try the following examples to extract the basename i.e. the last part of a path in Bash CLI:
$ my_file='/home/vivek/Documents/resume.pdf'
$ basename "$my_file"
Outputs
resume.pdf
Let us just get filename without suffix (extension):
$ pic="/home/vivek/bday-photo.jpg"
$ basename "$pic" .jpg
Outputs:
bday-photo
Try one more example to print your directory name:
$ my_dir="/home/vivek/projects/app1"
$ basename "$my_dir"
Outputs:
app1
The basename command is the most simple and recommended way for all Linux or Unix shell users. But bash offers some other syntax, too. Let’s see them.
Get filename without using basename command
The syntax is as follows for a parameter expansion:
$ FILE="/home/vivek/lighttpd.tar.gz"
$ printf "%s\n" "${FILE##*/}"
The real magic happens when you use "${FILE##*/} a parameter expansion that uses pattern removal. Let me break down that part for ease of understanding:
- ${FILE} : The FILE variable. This is a full (absolute) path to a file.
- ##*/ : This is the pattern being removed.
- # : This symbol, when doubled (##), means “remove the longest matching prefix pattern.” The pattern is defined next as */.
- */ : This is the pattern itself. It matches any string of characters (*) followed by a forward slash (/). In other word, it matches everything up to and including the last forward slash. Thus you end up getting only the filename itself.
Here is another example to get basename of filename or dir name under Linux or Unix-like systems:
$ url="https://www.cyberciti.biz/files/mastering-vi-vim.pdf"
$ echo "${url##*/}"
Basename a file with spaces using bash
Try the following examples (note the $input path has “App Server 2“):
$ input="/home/vivek/project/App Server 2/archive.jar"
$ f="${input##*/}"
$ echo "FULL PATH : $input"
$ echo "FILE : $f"
Outputs:
FULL PATH : /home/vivek/project/App Server 2/archive.jar FILE : archive.jar
Get running script name using bash parameter
The $0 will provide full path for currently running script. To extract that name only:
1 2 3 4 5 6 7 8 | #!/bin/bash_self="${0##*/}"echo "$_self is called"## or in usage() ##usage(){ echo "$_self: arg1 arg2"} |
Bash get a file extension
Try the following examples:
$ FILE="/home/vivek/lighttpd.tar.gz"
$ echo "${FILE#*.}" # print tar.gz
$ echo "${FILE##*.}" # print gz
$ ext="${FILE#*.}" # store output in a shell variable
$ echo "$FILE has $ext" # display it
Extracting the basename (the last part of a path) in Bash using awk
The syntax is simple:
# define path using $my_path variable my_path="/home/vivek/Videos/youtube-01-01-2018.mp4" # Now use awk to print 'youtube-01-01-2018.mp4' awk -F/ '{print $NF}' <<<"$my_path" # or # echo "$my_path" | awk -F/ '{print $NF}'
How to get the basename from the full filename path in bash
Use any one of the following syntax:
$ file="/home/vivek/.gpass/passwd.enc"
$ basename "$file"
$ echo "${file##*/}" # bash syntax
Let us just get the first part of the $file when you know that .enc is extension:
$ file="/home/vivek/.gpass/passwd.enc"
$ basename "$file" .enc
In this following example, I’m not using basename command. It is bash only syntax and when file extension is .enc, type:
$ t="/path/to/dir 1/filename.enc"
$ t="${t%.enc}"
$ echo "$t"
Script example to extract filename and extension in Bash
Try the following shell script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #!/bin/bash# Purpose: Compile latest Linux kernel# Author: Vivek Gite {https://www.cyberciti.biz/} # License: GPL version 2.0 or above# ---------------------------------------------------------------- set -e_out="/tmp/out.$$"dldir=~/linuxisdl=1 # do not downloadcurrent="$(uname -r)"curl -s https://www.kernel.org/ > "$_out"url="$(grep -A 2 '<td id="latest_button">' ${_out} | grep -Eo '(http|https)://[^/"]+.*xz')"gpgurl="${url/tar.xz/tar.sign}"file="${url##*/}"remote="${file%.tar.xz}"remote="${remote#linux-}"echo "* Current Linux kernel: $current"echo "* Remote Linux kernel version: $remote"[ "$current" = "$remote" ] || isdl=0if [ $isdl = 0 ]then notify-send "A new kernel version ($remote) has been released." echo "* Downloading new kernel ..." wget -qc "$url" -O "${dldir}/${file}" wget -qc "$gpgurl" -O "${dldir}/${gpgurl##*/}" echo "* Using gpg to verify new tar ball ..." cd "$dldir" xz -fd "$file" gpg --verify "${gpgurl##*/}" if [ $? -eq 0 ] then notify-send "Now compiling kernel ver $remote..." tar xf "${file%.xz}" cd "${file%.tar.xz}" cp -v "/boot/config-$(uname -r)" .config make -j $(nproc) && /usr/bin/notify-send "Password needed to install new kernel..." && sudo make modules_install && sudo make install && sudo reboot fifi |
A note about weird issues
Based on my years of experience in shell scripting, there are two edge cases where your bash script will fail. Let us document them for safety reasons.
- Handling spaces : If your filenames or directory names might contain spaces, enclosing them in double quotes (e.g., basename -- "$file") is crucial.
- Trailing slashes : Be aware that basename might behave differently on different Unix or Linux variant with trailing slash paths (e.g., /path/to/dir1/). Consider handling this case separately if it’s relevant to your needs. This is more of user input issue and basename variant.
Conclusion
You just learned how to get the basename and extension from the full filename when using Bash shell running on a Linux or Unix-like system. For more info see the following dirname command/basename command documentation using the help command or info command/man command:
$ man bash
$ info bash
$ man basename
🥺 Was this helpful? Please add a comment to show your appreciation or feedback.
there are file names and dir names with special chars such as spaces.
there is further the “dirname” application to do the vice versa.
a solution would be:
The results should be:
I added double quotes to examples to deal with filenames with spaces.
There is no “extension” in Unix, it is “suffix”.
Useful examples.
No sed example given on this page so here is my little contribution to open source community ;)