5

I would like to change lowercase filenames to uppercase with awk/sed/bash

your help would be appreciated

aaaa.txt
vvjv.txt
acfg.txt

desired output

AAAA.txt
VVJV.txt
ACFG.txt
rebca
  • 1,179
  • 3
  • 10
  • 11
  • 1.I used these tips to change my funny filenames with a bash one-liner: for i in ./*.*; do mv "$i" "$(echo "$i" | tr '[:?=&]' '[_]')"; done ; 2.Cross reference fyi to deal with even weird unicode chars: http://stackoverflow.com/questions/3011569/how-do-i-convert-filenames-from-unicode-to-ascii – AnneTheAgile May 10 '16 at 01:03

10 Answers10

19

PREFACE:

If you don't care about the case of your extensions, simply use the 'tr' utility in a shell loop:

for i in *.txt; do mv "$i" "$(echo "$i" | tr '[a-z]' '[A-Z]')"; done

If you do care about the case of the extensions, then you should be aware that there is more than one way to do it (TIMTOWTDI). Personally, I believe the Perl solution, listed here, is probably the simplest and most flexible solution under Linux. If you have multiple file extensions, simply specify the number you wish to keep unchanged. The BASH4 solution is also a very good one, but you must be willing to write out the extension a few times, or alternatively, use another variable to store it. But if you need serious portability then I recommend the last solution in this answer which uses octals. Some flavours of Linux also ship with a tool called rename that may also be worth checking out. It's usage will vary from distro to distro, so type man rename for more info.

SOLUTIONS:

Using Perl:

# single extension
perl -e 's/\.[^\.]*$/rename $_, uc($`) . $&/e for @ARGV' *.txt

# multiple extensions
perl -e 's/(?:\.[^\.]*){2}$/rename $_, uc($`) . $&/e for @ARGV' *.tar.gz

Using BASH4:

# single extension
for i in *.txt; do j="${i%.txt}"; mv "$i" "${j^^}.txt"; done

# multiple extensions
for i in *.tar.gz; do j="${i%.tar.gz}"; mv "$i" "${j^^}.tar.gz"; done

# using a var to store the extension:
e='.tar.gz'; for i in *${e}; do j="${i%${e}}"; mv "$i" "${j^^}${e}"; done

Using GNU awk:

for i in *.txt; do

    mv "$i" $(echo "$i" | awk '{ sub(/.txt$/,""); print toupper($0) ".txt" }');
done

Using GNU sed:

for i in *.txt; do

    mv "$i" $(echo "$i" | sed -r -e 's/.*/\U&/' -e 's/\.TXT$/\u.txt/');
done

Using BASH3.2:

for i in *.txt; do

    stem="${i%.txt}";

    for ((j=0; j<"${#stem}"; j++)); do

        chr="${stem:$j:1}"

        if [[ "$chr" == [a-z] ]]; then

            chr=$(printf "%o" "'$chr")

            chr=$((chr - 40))

            chr=$(printf '\'"$chr")
        fi

        out+="$chr"
    done

    mv "$i" "$out.txt"

    out=
done
Steve
  • 51,466
  • 13
  • 89
  • 103
  • n.b. sed solution not compatible with Mac/Darwin/BSD (non-Linux?) *sed* – Orwellophile Apr 19 '14 at 16:42
  • @Orwellophile: GNU sed is not BSD sed. BSD is Linux like GNU is Linux. – Steve Apr 20 '14 at 13:03
  • It doesn't work with Solaris either. (That's SYSV). But your correction is noted. It does not work with non-GNU versions of **sed** – Orwellophile Apr 25 '14 at 09:22
  • 1
    @Orwellophile: Correction? I stated the fact almost two years ago. If you have a non-GNU system, then you have other more serious problems than just the case of your filenames. – Steve Apr 25 '14 at 13:56
9

In general for lowercase/upper case modifications "tr" ( translate characters ) utility is often used, it's from the set of command line utilities used for character replacement.

dtpwmbp:~ pwadas$ echo "xxx" | tr '[a-z]' '[A-Z]'
XXX
dtpwmbp:~ pwadas$ 

Also, for renaming files there's "rename" utility, delivered with perl ( man rename ).

    SYNOPSIS
       rename [ -v ] [ -n ] [ -f ] perlexpr [ files ]

DESCRIPTION
       "rename" renames the filenames supplied according to the rule specified as the first argument.  The perlexpr argument is a Perl expression which is expected to modify the $_ string in
   Perl for at least some of the filenames specified.  If a given filename is not modified by the expression, it will not be renamed.  If no filenames are given on the command line,
   filenames will be read via standard input.

   For example, to rename all files matching "*.bak" to strip the extension, you might say

           rename 's/\.bak$//' *.bak

   To translate uppercase names to lower, you'd use

           rename 'y/A-Z/a-z/' *
Piotr Wadas
  • 1,838
  • 1
  • 10
  • 13
6

I would suggest using rename, if you only want to uppercase the filename and not the extension, use something like this:

rename -n 's/^([^.]*)\.(.*)$/\U$1\E.$2/' *

\U uppercases everything until \E, see perlreref(1). Remove the -n when your happy with the output.

Thor
  • 45,082
  • 11
  • 119
  • 130
  • You might add ^ and $ anchors, and explicitly require the '.', so the match doesn't depend on the regex section being greedy or lazy; just makes it more readable IMHO. – Clayton Stanley Sep 19 '12 at 00:56
  • That fits better with what the OP wants. I've added your suggestions – Thor Sep 19 '12 at 07:30
1
for f in *.txt; do
  mv "$f" "`tr [:lower:] [:upper:] <<< "${f%.*}"`.txt"
done
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
1

Bash 4 parameter expansion can perform case changes:

for i in *.txt; do
  i="${i%.txt}"
  mv "$i.txt" "${i^^?}.txt"
done
chepner
  • 497,756
  • 71
  • 530
  • 681
1

bash:

for f in *.txt; do 
    no_ext=${f%.txt}
    mv "$f" "${no_ext^^}.txt"
done
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
1

An easier, lightweight and portable approach would be:

for i in *.txt
do 
    fname=$(echo $i | cut -d"." -f1 | tr [a-z] [A-Z])
    ext=$(echo $i | cut -d"." -f2)
    mv $i $fname.$ext
done

This would work on almost every version of BASH since we are using most common external utilities (cut, tr) found on every Unix flavour.

Ashish Kumar
  • 811
  • 4
  • 8
1

Simply use (on terminal):

for i in *.txt; do mv $i `echo ${i%.*} | tr [:lower:] [:upper:]`.txt; done;
Vasu
  • 4,862
  • 8
  • 42
  • 48
0

This might work for you (GNU sed):

printf "%s\n" *.txt | sed 'h;s/[^.]*/\U&/;H;g;s/\(.*\)\n/mv -v \1 /' | sh

or more simply:

printf "%s\n" *.txt | sed 'h;s/[^.]*/\U&/;H;g;s/\(.*\)\n/mv -v \1 /e'
potong
  • 55,640
  • 6
  • 51
  • 83
0
for i in *.jar; do mv $i `echo ${i%} | tr [:upper:] [:lower:]`; done;  

this works for me.

NOZUONOHIGH
  • 1,892
  • 1
  • 20
  • 20