How can I use rename to recursively rename everyting to uppercase

I’d like to recursively rename all files and folders (sub-folders) to uppercase.

I found some scripts that will do it to lowercase, but I don’t know how to change them so it will do it the other way around (lower to upper).

The script that I found and works for lowercase, but I didn’t knew how to modify is:

rename 'y/A-Z/a-z/' *

It’s from man rename.

Stolen (with a minor edit) from Gilles post here

find <DIR> -depth -type d -exec rename -n 's!/([^/]*/?)$!U/$1!' {} +

Answered By: Warwick

Try this after moving to directory where you would like to rename the files:

for word in `ls -ltr |tail -n +2 |awk '{print $9}'`
do
  a=$(echo $word | tr '[a-z]' '[A-Z]')
  mv $word $a
  echo "Done Successfully"
done
Answered By: Sorav

Note that you’re using the Perl script called rename distributed by Debian and derivatives (Ubuntu, Mint, …). Other Linux distributions ship a completely different, and considerably less useful, command called rename.

y/A-Z/a-z/ translates each character in the range A through Z into the corresponding character in the range a through z, i.e. ASCII uppercase letters to the corresponding lowercase letter. To perform the opposite translation, use y/a-z/A-Z/. Another way to write the same command is rename '$_ = uc($_)' * — uc is the uppercase function, and the rename command renames files based on the transformation made to the $_ variable.

rename '…' * only renames files in the current directory, because that’s what * matches. Dot files (files whose name begins with .) are skipped, too.

If you want to rename files in the current directory and in subdirectories recursively, you can use the find command to traverse the current directory recursively. There is a difficulty here: if you call rename, this renames both the directory and the base name part. If you call rename on a directory before recursing into it (find -exec rename … {} ;), find gets confused because it’s found a directory but that directory no longer exists by the time it tries to descend into it. You can work around this by telling find to traverse a directory before acting on it, but then you end up attempting to rename foo/bar to FOO/BAR but the directory FOO doesn’t exist.

A simple way to avoid this difficulty is to make the renaming command act only on the base name part of the path. The regular expression ([^/]*Z) matches the final part of the path that doesn’t contain a /.

find . -depth -exec rename 's!([^/]*Z)!uc($1)!e' {} +

The shell zsh provides more convenient features for renaming — even more cryptic than Perl, but terser and often easier to compose.

The function zmv renames files based on patterns. Run autoload -U zmv once to activate it (put this line in your .zshrc).

In the first argument to zmv (the pattern to replace), you can use zsh’s powerful wildcard patterns. In the second argument to zmv (the replacement text), you can use its parameter expansion features, including history modifiers.

zmv -w '**/*' '$1$2:u'

Explanation:

  • -w — automatic assign numeric variables to each wildcard pattern
  • **/* — all files in subdirectories, recursively (**/ matches 0, 1 or more levels of subdirectories)
  • $1 — the first numeric variable, here matching the directory part of each path
  • $2:u — the second numeric variable, here matching the base name part of each path, with the :u modifier to convert the value to uppercase

As an added bonus, this respects the ambient locale settings.

If you aren’t sure about a zmv command you wrote, you can pass the -n option to print what the command would do and not change anything. Check the output, and if it does what you want, re-run the command without -n to actually act.

find -execdir rename

This renames files and directories with a regular expression affecting only basenames.

So for a prefix you could do:

PATH=/usr/bin find . -depth -execdir rename 's/(.*)/U$1/' '{}' ;

or to affect files only:

PATH=/usr/bin find . -type f -execdir rename 's/(.*)/U$1/' '{}' ;

-execdir first cds into the directory before executing only on the basename.

I have explained it in more detail at: https://stackoverflow.com/questions/16541582/find-multiple-files-and-rename-them-in-linux/54163971#54163971

I’d like to direct anyone who’s still being linked to this answer to the excellent answer Guiles Quernot gave to this question which doesn’t require find.

The resulting command would be:

shopt -s globstar
rename -n 'y/a-z/A-Z/' **

But before running please read the answer linked for caveats regarding old bash versions.

Finally in case someone is wondering what does the y/// command does in perl regex. Here’s a link to the relevant documentation.

Answered By: Marcelo Lacerda

A solution without using rename (which is not available in some distro’s):

find <dir> -type d -printf "echo mv %h/%f %h/$(echo %f | sed 's/(.*)/U$1/')n" | sort -r -k3,3 | sh

for testing and to do actual work :

find <dir> -type d -printf "mv %h/%f %h/$(echo %f | sed 's/(.*)/U$1/')" | sort -r -k2,2 | sh

Explanation:
Look in current folder (find .) and find all directories (-type d) which and print a command which will be passed to sh for execution. printf replaces %h and %f with path-to and name of found folders. The part $(echo %f | sed 's/(.*)/U$1/g') asks the sed command to replace (s/) anything and take them as group 1 ((.*)) and replace it with uppercaseed group 1 (U$1) in folder name. The important part is to reverse sort (| sort -r) these commands by the source path only (-k2,2) before running them (| sh) otherwise you may have renamed a parent folder before renaming it’s child and the command fails and the -k2,2 ensures extra parts does not mingle with sorting. (try these commands to understand the reason printf "./a/b n./a n./c/a n./a/a n./c/a/a n" |sort and printf "./a/b tn./a tn./c/a tn./a/a tn./c/a/a tn" |sort)
Note: it may fail if the folders names have white spaces

Answered By: PMN
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.