Convert Filenames to Lowercase
Back in the good old days, there was an operating system that didn't seem to think NAME and name were different. The result was that sometimes when you transfered files from a floppy disk (remember them?) created on that Dumb Old System, you would clutter your directory with uppercase filenames. As us UNIX old-timers learned a nifty trick to get directory names to sort before filenames in the output of the ls command (namely, start directory names with an uppercase letter), having filenames with uppercase letters was irritating.
After using the mv command all too many times and typing things like mv FILE.TXT file.txt, I wrote this script. I was thinking I could put a new coat of paint on it but, in reality, it does the job and is easy to understand. (The line numbers are there, of course, just for reference.)
1 #!/bin/sh
2 # lowerit
3 # convert all file names in the current directory to lower case
4 # only operates on plain files--does not change the name of directories
5 # will ask for verification before overwriting an existing file
6 for x in `ls`
7 do
8 if [ ! -f $x ]; then
9 continue
10 fi
11 lc=`echo $x | tr '[A-Z]' '[a-z]'`
12 if [ $lc != $x ]; then
13 mv -i $x $lc
14 fi
15 done
Line 6 starts a loop (which ends with line 15). The ls command returns a list of filenames which are sequentially assigned to the shell variable x. The if test (lines 8 through 10) checks to see if the current filename is that of a plain file. If not, the remainder of the statements in the current loop iteration are skipped.
If line 11 is to be executed we know that we have an ordinary file. Using tr we convert the filename to lowercase and assign the new name to the shell variable lc. Line 12 then checks to see if the lowercase version of the name differs from the original. If it does, line 13 is executed to change the name of the original file to the new lowercase name. The -i option causes the mv to prompt for confirmation if executing the command would overwrite an existing filename.
Phil Hughes
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Designing Electronics with Linux | May 22, 2013 |
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
- New Products
- Linux Systems Administrator
- Senior Perl Developer
- Technical Support Rep
- Web & UI Developer (JavaScript & j Query)
- UX Designer
- Designing Electronics with Linux
- Dynamic DNS—an Object Lesson in Problem Solving
- Using Salt Stack and Vagrant for Drupal Development
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Nice article, thanks for the
2 hours 27 min ago - I once had a better way I
8 hours 13 min ago - Not only you I too assumed
8 hours 30 min ago - another very interesting
10 hours 24 min ago - Reply to comment | Linux Journal
12 hours 17 min ago - Reply to comment | Linux Journal
19 hours 11 min ago - Reply to comment | Linux Journal
19 hours 27 min ago - Favorite (and easily brute-forced) pw's
21 hours 18 min ago - Have you tried Boxen? It's a
1 day 3 hours ago - seo services in india
1 day 7 hours ago
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Featured Jobs
| Linux Systems Administrator | Houston and Austin, Texas | Host Gator |
| Senior Perl Developer | Austin, Texas | Host Gator |
| Technical Support Rep | Houston and Austin, Texas | Host Gator |
| UX Designer | Austin, Texas | Host Gator |
| Web & UI Developer (JavaScript & j Query) | Austin, Texas | Host Gator |
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?



Comments
Thanks, this was helpful, the
Thanks, this was helpful, the script did a good job ;)
zshell
Hello there, great job but i use other way:
It includes using Zshell [ zsh ] an is as simple as:
zmv '(*)' '${(L)1}'
Have a good day.
Now we have convmv
I have made my own scripts (tolower, toupper) back in the early 1990's, but now we have convmv:
convmv --lower --notest *
(note the --notest - the default is to show the actions instead of doing it)
It can also convert character sets, including - but not limited to - UTF-8 normalization forms C (Linux and many others) and D (Mac OS X).
thanks...
thanks, convmv works great
Better lowercase mousetrap
For handling names with spaces, and not being limited to all of the current directory, use parameters, eg * or *.jpg or whatever, try:
#!/bin/bash
while [ "$1" ] ; do
f="$1"
shift
echo -ne "\n$f:"
if [ -f "$f" ]; then
echo -n "(file) "
lc=`echo $f | awk '{print(tolower($0));}'`
if [ "$lc" != "$f" ]; then
echo "-> '$lc'"
mv -i "$f" "$lc"
fi
fi
done
Have a C program to do something similar
Hey,
not much of a script writer myself, but I have something like this in a suit of shell utilities I wrote
hosted at:
ioe.sf.net
also includes nifty tools for command line image processing - useful in conjunction with netpbm.
unfortunately, I don't use a lot of standard libraries and reimplemented things myself for learning purposes, but its all good.
Good information in the comments
There is a lot of good information in the comments. Note that if I were to write the script today I would do it different. At the time (I don't know when I really wrote it--the date was a filesystem timestamp on an LS-120 disk I was reading so I am pretty sure it was written years before that--it was to convert MS-DOS file names to lower case. Thus, some of the concerns (such as a space in a filename) were just not considerations.
Phil Hughes
Next line works only for
Next line works only for english
lc=`echo $x | tr '[A-Z]' '[a-z]'`
Please use next line for real lowercase:
lc=`echo $x | awk '{print(tolower($0));}'`
another way
for i in *
do
mv -f "$i" `echo "$i" | tr A-Z a-z`
done
Slight improvement for extended chars...
Not sure if this will work for unicode but it should at least handle latin charset beyond the a-z range - change:
lc=`echo $x | tr '[A-Z]' '[a-z]'`
to
lc=`echo $x | tr "[:upper:]" "[:lower:]"`
Why not simply use rename ?
Hi there ! =)
This can also be done easier with the "rename" tool that ships with perl:
rename 's/.*/-f&&lc||$_/e' *well, shorter at least :-)
regards, Simon
lower case, use rename
Alternatively, if your distro happens to include the "rename" command you can simply do this:
~$ rename 'y/A-Z/a-z/' *
That sets all files in the current directory to lower case. 'natch.
D.
--
rename
If available on your system "rename" is also a very nice command. It is able to handle regular expressions. For example to lowercase all files ending with ".txt" you could use this one command:
rename 'y/A-Z/a-z/' *.txt
You can find more information on this page:
renaming multiple files
Bugs in this script
This script will not perform correctly, and can even be dangerous to use, because it doesn't properly handle special characters in filenames. What if the filenames contain single quotes, or double quotes, or spaces, or asterisks, or combinations of such? An extreme case is when a file is called "* a"...
a safer version
nice script, however lines 8 and 12 are unsafe (will break for file names with embedded spaces... so it's kinda a bug ;-)
double square brackets test will always work:
[[ -f $fileName ]] && ...
if you prefer to stick to old 1998 test, wrap the test parameters in double quotation marks.
I used to have a little
I used to have a little alias for the job using xargs, but now I just use:
rename 'y/A-Z/a-z/' *
Hi, Brent! That's cool!
Hi, Brent! That's cool!
It's called Perl rename
since it uses Perl regex to do the whole thing. Also, you can use this to rename files with some pattern -- that's why regex was created and I love it!
Here's a Python version that does a bit more
Not sure if you're just focused on the bash way to do this. I wrote something like this a while back in Python that I've found pretty useful, especially for music collections. It does some other name normalization, too.
Micah Elliott | http://MicahElliott.blogspot.com
Use of `ls`
What advantage is there in using:
for x in `ls`over
for x in *?
There isn't an advantage, in
There isn't an advantage, in fact it's more of a disadvantage due to bash's word splitting. It won't work if your filenames have spaces. See the following example:
$ touch "file-without-spaces" "file with spaces"
$ for i in *; do echo "--- $i ---"; done
--- file-without-spaces ---
--- file with spaces ---
$ for i in `ls`; do echo "--- $i ---"; done
--- file-without-spaces ---
--- file ---
--- with ---
--- spaces ---
I always change the IFS var
I always change the IFS var when dealing with files with spaces
IFS=$'\n'
for FILES in $(find /some/dir)
do
echo $FILES
done
while read i
Personally I've grown accustomed to:
/bin/ls | while read i; do blah blah "$i" | foo >> bar.out doneMy "smv" (sed + mv) bash function looks like:
function smv () { if [ "$#" -lt 2 ]; then echo "Usage: smv 's/pat/tern/' [ ...]" 1>&2 return else local pattern pattern="$1"; shift while [ "$#" -ge 1 ]; do new=`echo "$1" | sed -e "$pattern"` echo mv \"$1\" \"$new\" mv "$1" "$new" shift done fi }None, however he's using sh,
None, however he's using sh, not bash.
"for x in *" is is far better, as would using [['s be better, since he's not even quoting his variables.
Best still, he could just be using the tool rename, most distros have it available for installing.
My "tolower" Perl script
#!/usr/bin/perl -s if(@ARGV == 0) { opendir PWD, "."; @ARGV = readdir PWD; closedir PWD; } foreach (@ARGV) { # skip if no upper case! next unless /[[:upper:]]/; warn "# starting \"$_\"\n" if $v; # verbose mode next if $_ eq "."; next if $_ eq ".."; next if m#.*/\.\.?$#; $pathname = $_; warn "# Doing \"$pathname\"\n" if $v; # verbose mode if($r && -d $_ && /^[^\/]+$/) { print "# visiting directory $_\n"; opendir DIR, $_; my @dir = readdir DIR; closedir DIR; foreach my $entry (@dir) { next if $entry eq ".."; next if $entry eq "."; warn "# Adding $_/$entry\n" if $v; # verbose mode unshift @ARGV, "$_/$entry"; } warn "# Redo-ing\n" if $v; # verbose mode redo; } if(($dir, $filename) = m!(.*/)(.*)!) { $_ = $filename; } else { $dir =""; } # unicode-friendly way to do equivalent of English [A-Z] -> [a-z] s/[([:upper:])]/\L$1\E/g; print "mv $pathname $dir$_\n"; $xx="xx01"; unless($n) { if(-e "${dir}${xx}.$$") { # leave it there, increment xx $xx++; if(-e "${dir}${xx}.$$") { die "\"${dir}${xx}.$$\" no longer safe. Quitting.\n"; } } print "# moving \"$pathname\" to \"${dir}${xx}.$$\"\n" if $v; # verbose mode # rename twice in case of case-insensitive file systems rename($pathname, "${dir}${xx}.$$") || print "# couldn't rename \"$pathname\" to \"${dir}${xx}.$$\": $!\n"; print "# moving \"${dir}${xx}.$$\" to \"$dir$_\"\n" if $v; # verbose mode rename("${dir}${xx}.$$", "$dir$_") || print "# couldn't rename \"${dir}${xx}.$$\" to \"$dir$_\": $!\n"; } } exit(0);Many ways to do this:
This:
rename 'y/A-Z/a-z/' *is clearly the tersest, but there are other ways.