Extract Filename without Extension from Full Path in Bash

Written by: Bobbin Zachariah   |   Last updated: May 28, 2023

1. Introduction

In this tutorial, we delve into the world of bash scripting and explore techniques to extract filenames from file paths while trimming the extension. We cover essential tools like basename, parameter expansion, cut, awk, and sed, highlighting their unique features and applications. By mastering these methods, you'll gain the ability to efficiently manipulate filenames in bash scripts, enabling tasks such as renaming and copying files with ease.

2. Using basename

As we gathered, the sole role of the bash command is to give us the file name from the path. But if the file name has an extension, we get that too. We can still use the command to get rid of the extension or any suffix. This ensures we end up a clean output of just the name of the file.

Example:

basename /home/ubuntu/sample.txt .txt
basename -s .txt /home/ubuntu/sample.txt
Command output: 'sample' - basename /home/ubuntu/sample.txt .txt

We are aware the command accepts two syntaxes. They are just a different way of writing. In the first one we have to provide the path and the extension we want to be trimmed from the final output. In the latter case, we have the -s option which accepts the extension we want to remove. 

In both cases, the basename should produce the result "sample.txt". As we have provided the suffix, the output will be trimmed further by removing the .txt from the result. We will get the final output "sample". If we provide an imaginary suffix or one that is not at the end, the outcome remains the same. It will assume there was no suffix.

We can, with certain limitations, combine -s and -a flag to trim extensions from multiple inputs.

Example:

basename -as .txt /home/ubuntu/readmecopy.txt /home/ubuntu/readme.txt
basename -as .txt /home/ubuntu/readmecopy.txt /home/ubuntu/config.cfg
Output of basename command: removing '.txt' suffix from '/home/ubuntu/readmecopy.txt' and '/home/ubuntu/readme.txt'

In the first case, we have asked the command to remove the .txt extension from multiple inputs. But there is a loophole. We cannot assign individual suffices. That won’t work. Our hand is forced as we can only provide one suffix to all the file paths.

If multiple files with different extensions exist, then it will trim the ones whose extensions match with the supplied. In our case, we get "sample" and "sample.cfg" as the eventual output. They will be separated by a line break.

3. Using parameter expansion

We saw how parameter expansions work above and how we can use it to extract the file name with the extension. But we might only be interested in the file name. We can still proceed with it.

Example:

filepath=/home/ubuntu/sample.txt
filename=$(basename $filepath)
echo ${filename%.*}
using parameter expansion - Extracting filename without extension

The above example can be generalized as follows:

${variable%pattern}

This trims the shortest match from the end of the pattern. It displays whatever is after the pattern. The shortcoming again is that we need a variable because of the parameter expansion.

In our example, we have extracted the filename from the file path using the basename command. Then we used the parameter expansion.

We have used the regex (*) as the pattern. We have also added the dot (.) before the regular expression. This dot represents the beginning of the extension.

Bash will look for all the characters from the last dot and trim it. Hence, we will get the characters before the final dot. This gives us just the name of the file.

4. Using powerful Bash tools

We talked about utilizing the powerful built-in tools to fetch the file name. They may appear complex at first. Let us understand them one by one and how we can integrate the regular expressions.

4.1 Using cut

Example:

path="/home/ubuntu/contents.tar.gz"
echo "$path" | cut -f 1 -d '.' | tr '/' '\n' | tail -1
cut command -  Extracting filename without extension

Cut is a very straightforward tool. And it comes in handy in our case to extract the file name. We have combined it with some of the readily available tools- tr and tail.

In our example, we pipe the result of the echo command so that Bash can send it as an input to the cut command. The cut command uses the delimiter (-d) as the dot (.) for extension. This splits the string into two parts- one before the dot and the other after.

The -f 1 option ensures that Bash opts for the former. This is then sent to the tr command which substitutes the path separator with line breaks. From this we have to pick the last line. Tail -1 does that job for us.

To sum up our example:

  • Cut makes /home/ubuntu/contents.tar.gz become /home/ubuntu/contents
  • Tr breaks /home/ubuntu/contents into 3 different lines
    home
    ubuntu
    Contents
  • Tail prints contents 

4.2 Using awk

Example:

path="/home/ubuntu/sample.txt"
echo "$path" | awk -F '/' '{sub(/[.][^.]*/,"",$NF); print $NF}'
using awk - Extracting filename without extension

In this example, we have taken a variable to hold the entire file path. We are free to supply that string directly to the echo command. We pipe the result of this echo command so that Bash can send it as an input to the awk command.

The -F option available with the awk command acts as the field separator. We have built the regular expression for the awk statement in such a way that the string dissociates into two halves from the final slash (/).

We then pick the last half of the field using $NF. This will contain the filename without the path information. Next, we call the available function with awk- sub(). This clears the file extension and prints the result as the filename.

4.3 Using sed

Example:

path="/home/ubuntu/sample.txt"
echo $path | sed 's|.*/||; s|[.][^.]*$||'
usind sed - Extracting filename without extension

In this example as well, we store the entire file path in a variable. We can also feed the string directly to the echo command. We pipe the result of this echo command, which becomes the input to the sed command.

After that it is just a case of providing the right regular expression to the command. The s option with the flag is used to tell Bash that sed wants to carry out substitution. We have taken the symbol | to act as a separator for the sed syntax. This character may be uniformly replaced by any other single character within any given s command.

We have used two regular expressions here:

s|.*/|| : This expression ends up removing everything till the last slash. This is the parent directory of the file.

s|[.][^.]*$|| – This regular expression trims everything after the last dot. This gets rid of the file’s extension.

We can notice that the core regular expression /[^.]*$ in the above awk command and here has remained the same. 

5. Example Script

As we have learned different ways of fetching the name of the file, we can look at an example that prompts the user to provide the complete path of the file. The script checks the existence of the file. It then asks the user to provide the extension so that the script can create a copy of the same file with a different extension.

#!/bin/bash 

read -p "Enter the filename with it's complete path: " fpath


if [ ! -f "$fpath" ]
then
	echo "Invalid file. Please check the input."
else
	read -p "Enter the new extension you want: " ext
	fname=`basename $fpath`
	fname=`echo ${fname%.*}`
	dname=`dirname $fpath`
	cp $fpath ${dname}/${fname}.${ext}


fi
Bash script: Prompting user to enter a file path, changing extension, and copying the file

1. The script starts by asking the user to enter the filename with its complete path using the read command. The entered value is stored in the fpath variable.

2. The script checks if the file specified by fpath does not exist using the -f test condition. If the file doesn't exist, it prints "Invalid file. Please check the input."

3. If the file exists, the script prompts the user to enter the new extension. This response is stored in the ext variable.

4. The script pulls out the name of the file with the extension using the basename command. Using backticks technique, it stores the response of the command in the variable fname.

5. It then uses the parameter expansion to get rid of the extension. This gives just the filename and the script overwrites the variable fname with this value. 

6. Similarly, the script utilizes the dirname command to get the directory path from the user input present in fpath. The variable dname stores the output of the dirname command.

7. Finally, the script copies the file from the location in fpath to the destination ${dname}/${fname}/${ext}.

8. This ensures that the file is copied in the same location with the same name and with a user-provided extension.

About The Author

Bobbin Zachariah

Bobbin Zachariah

Bobbin Zachariah is an experienced Linux engineer who has been supporting infrastructure for many companies. He specializes in Shell scripting, AWS Cloud, JavaScript, and Nodejs. He has qualified Master’s degree in computer science. He holds Red Hat Certified Engineer (RHCE) certification and RedHat Enable Sysadmin.

SHARE

Comments

Please add comments below to provide the author your ideas, appreciation and feedback.

Leave a Reply

Leave a Comment