Home > Software engineering >  How can I remove the extension of specific files in a directory?
How can I remove the extension of specific files in a directory?

Time:01-23

I want to remove the extension of specific files with a given extension.

So for instance, in a directory foobar, we have foo.txt, bar.txt foobar.jpg.

Additionally, the extension that I've put in to be removed is txt

After calling the program, my output should be foo bar foobar.jpg

Here is my code so far:

#!/bin/bash
echo "Enter an extension"
read extension
echo "Enter a directory"
read directory
for file in "$directory"/*; do      //
        if [[ $file == *.txt ]]
        then
                echo "${file%.*}"
        else
                echo "$file"

        fi

done

However when I run this on a given directory, nothing shows up.

I'm assuming that there is a problem with how I referred to the directory ( in the line where I placed a //) and I've tried to research on how to solve it but to no avail.

What am I doing wrong?

CodePudding user response:

If files do exist in a valid directory you've entered then they should show up — with one exception. If you are using ~/ (shorthand home directory) then it will be treated as plain text in your for loop. The read variable should be substituted into another variable so the for loop can treat it as a directory (absolute paths should work normally as well).

#!/bin/bash

echo "Enter an extension"
read -r extension
echo "Enter a directory"
read -r directory
dir="${directory/#\~/$HOME}"
for file in "$dir"/*; do
        if [[ $file == *."$extension" ]]
        then
                echo "${file%.*}"
        else
                echo "$file"
        fi
done

CodePudding user response:

You can simplify your for-loop:

for file in "$directory"/*; do
    echo "${f%.$extension}";
done

The % instructions removes only matching characters. If nothing matches, the original string (here f) is returned.

CodePudding user response:

When you write bash scripts it's more common to pass arguments to your script via command line arguments rather than by reading it from standard input via read program.

Passing arguments via command line:

#!/bin/bash

# $# - a bash variable  which holds a number of arguments passed 
# to script via command line arguments

# $0 holds the name of the script

if [[ $# -ne 2 ]]; then # checks if exactly 2 arguments were passed to script
    echo "Usage: $0 EXTENSION DIRECTORY"
    exit -1;
fi

echo $1; # first argument passed to script
echo $2; # second arugment passed to script

This approach is more efficient because a subprocess is spawn for read command to run and there is no subprocess spawn for reading command line arguments.

There is no need to manually loop through directory, you can use find command to find all files with given extension within given directory.

find /path/to/my/dir -name '*.txt' 

find $DIRECTORY -name "*.$EXTENSION" 
# note that  single quotes in this context would prevent $EXTENSION
#  variable to be resolved, so double quotes are used " "

# find searches for files inside $DIRECTORY and searches for files 
# matching pattern '*.$EXTENSION'

Note that to avoid bash filename expansion sometimes it is required to wrap actual pattern in single quotes ' ' or double quotes " ". See Bash Filename Expansion

So now your script can look like this:

#!/bin/bash
if [[ $# -ne 2 ]]; then 
    echo "Usage: $0 EXTENSION DIRECTORY"
    exit -1;
fi

$EXTENSION = $1 #  for better readability
$DIRECTORY = $2

for file in `find $DIRECTORY -name "*.$EXTENSION"`; do
   mv $file ${file%.$EXTENSION}
done

Construct ${file%.$EXTENSION} is called Shell Parameter Expansion it searches for occurrence of .$EXTENSION inside file variable and deletes it.

Notice that in the script it is easy to pass extension as directory and vice versa.

We can check if second argument is in fact directory, we can use following construction:

if ! [[ -d $DIRECTORY ]]; then
    echo $DIRECTORY is not a dir
    exit -1
fi

This way we can exit from the script earlier with more readable error.

To sum up entire script could look like this:

#!/bin/bash
if [[ $# -ne 2 ]]; then 
    echo "Usage: $0 EXTENSION DIRECTORY"
    exit -1;
fi

EXTENSION=$1 #  for better readability
DIRECTORY=$2

if ! [[ -d $DIRECTORY ]]; then
    echo $DIRECTORY is not a directory.
    exit -1
fi

for file in `find $DIRECTORY -name "*.$EXTENSION"`; do
   mv $file ${file%.$EXTENSION}
done

Example usage:

$ ./my-script.sh txt /path/to/directory/with/files
  • Related