Bash – Convert only parts of a filename to uppercase

bashexprfilenamesregular expressionshell

In a shell script program, I need to convert the filenames to uppercase if the converted filename does not already exist. In this particular case I need to change only the basename to uppercase leaving the extension (if any) as it is.

My idea of doing the problem is to extract first the basename and the extension separately, convert the basename to uppercase using
tr command and then check whether the changed basename along with the extension exists in the directory or not.

If it does not exist then I will change the original filename with the uppercase basename using mv. Now I think that this can be done in two ways: firstly using expr and secondly using cut with . (space-period-space) as the delimiter.

If I want to use expr for extracting the basename (for eg. from the filename – python1.py or phonelist) then I have written this:

basefile=`expr "$filename" : '\(.*\)\.*.*' ` 

I have used \.* for those filenames also which do not have any extension because \.* would ignore zero or more occurrences of ., but this expression for expr is not working properly. For any filename, it is returning the whole filename as it is.

Can anyone please explain where am I wrong. Also please suggest how can I use expr to extract only the extension from the filename.

Best Answer

If the shell is bash, using just bash parameters expansion:

file="aaa.bbb.dat"

name=${file%.*} # delete everything after last dot 
ext=${file##*.} # delete everything up to last dot
upcase=${name^^*}.$ext # uppercase everything

echo "$upcase"
AAA.BBB.dat

Trying with a more difficult case:

file="déjà vu . dat "
name=${file%.*} # delete everything after last dot 
ext=${file##*.} # delete everything up to last dot
upcase=${name^^*}.$ext # uppercase everything
echo ":$upcase:"

Gives:

:DÉJÀ VU . dat :

So:

  • double quotes aren't necessary, until using the result
  • Uppercase seems OK even for non-ASCII characters
Related Question