0

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?

Droid
  • 520
  • 1
  • 7
  • Run your program with `set -x` and analyze the output (this is just for debugging; you can remove it when it works). Also a `shopt -s failglob` at the start of the script will most likely help you. BTW, you are setting a variable `extension`, but never use it. This also should make you think. – user1934428 Jan 23 '23 at 09:54

3 Answers3

0

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
l'L'l
  • 44,951
  • 10
  • 95
  • 146
  • If you need to worry about `~`, then there's also `~user` and some other bash-isms like `~+` and `~-` to consider. cf. https://stackoverflow.com/a/29310477/10971581 – jhnc Jan 23 '23 at 10:41
  • Thank you, one question though, what would happen if I do not use ~/ ? – Droid Jan 23 '23 at 10:41
  • and also why did u create a new variable dir? Would there be a problem if I did not create it? – Droid Jan 23 '23 at 10:42
0

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.

Wiimm
  • 2,971
  • 1
  • 15
  • 25
0

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