Change Filenames to Lowercase in Ubuntu in All Subdirectories

How do I rename all folders and files to lowercase on Linux?

A concise version using the "rename" command:

find my_root_dir -depth -exec rename 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \;

This avoids problems with directories being renamed before files and trying to move files into non-existing directories (e.g. "A/A" into "a/a").

Or, a more verbose version without using "rename".

for SRC in `find my_root_dir -depth`
do
DST=`dirname "${SRC}"`/`basename "${SRC}" | tr '[A-Z]' '[a-z]'`
if [ "${SRC}" != "${DST}" ]
then
[ ! -e "${DST}" ] && mv -T "${SRC}" "${DST}" || echo "${SRC} was not renamed"
fi
done

P.S.

The latter allows more flexibility with the move command (for example, "svn mv").

Change filenames to lowercase in Ubuntu in all subdirectories

Here's one way using find and tr:

for i in $(find . -type f -name "*[A-Z]*"); do mv "$i" "$(echo $i | tr A-Z a-z)"; done

Edit; added: -name "*[A-Z]*"

This ensures that only files with capital letters are found. For example, if files with only lowercase letters are found and moved to the same file, mv will display the are the same file error.

How to change filenames to lowercase?


for file in *; do
[[ -f "$file" ]] && mv "$file" "${file,,}" 2>/dev/null
done

I'm not sure what version of bash introduced the ${var,,} expansion.

Recursively convert all folder and file names to lower-case or upper-case

I realize you want ruby code, but I present to you a one liner to run in your shell:

for i in `find * -depth`; do (mv $i `echo $i|tr [:upper:] [:lower:]`); done

as found here: http://ubuntuforums.org/showthread.php?t=244738

Run it once, and it should do the trick.

Update

Ruby Code:

Dir.glob("./**/*").each do |file|
File.rename(file, file.downcase) #or upcase if you want to convert to uppercase
end

Convert all file extensions to lower-case

Solution

You can solve the task in one line:

find . -name '*.*' -exec sh -c '
a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$0" ] && mv "$0" "$a" ' {} \;

Note: this will break for filenames that contain newlines. But bear with me for now.

Example of usage

$ mkdir C; touch 1.TXT a.TXT B.TXT C/D.TXT
$ find .
.
./C
./C/D.TXT
./1.TXT
./a.TXT
./B.TXT

$ find . -name '*.*' -exec sh -c 'a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/"); [ "$a" != "$0" ] && mv "$0" "$a" ' {} \;

$ find .
.
./C
./C/D.txt
./a.txt
./B.txt
./1.txt

Explanation

You find all files in current directory (.) that have period . in its name (-name '*.*') and run the command for each file:

a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$0" ] && mv "{}" "$a"

That command means: try to convert file extension to lowercase (that makes sed):

$ echo 1.txt | sed -r "s/([^.]*)\$/\L\1/"
1.txt
$ echo 2.TXT | sed -r "s/([^.]*)\$/\L\1/"
2.txt

and save the result to the a variable.

If something was changed [ "$a" != "$0" ], rename the file mv "$0" "$a".

The name of the file being processed ({}) passed to sh -c as its additional argument and it is seen inside the command line as $0.
It makes the script safe, because in this case the shell take {} as a data, not as a code-part, as when it is specified directly in the command line.
(I thank @gniourf_gniourf for pointing me at this really important issue).

As you can see, if you use {} directly in the script,
it's possible to have
some shell-injections in the filenames, something like:

; rm -rf * ;

In this case the injection will be considered by the shell as a part of
the code and they will be executed.

While-version

Clearer, but a little bit longer, version of the script:

find . -name '*.*' | while IFS= read -r f
do
a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$f" ] && mv "$f" "$a"
done

This still breaks for filenames containing newlines. To fix this issue, you need to have a find that supports -print0 (like GNU find) and Bash (so that read supports the -d delimiter switch):

find . -name '*.*' -print0 | while IFS= read -r -d '' f
do
a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$f" ] && mv "$f" "$a"
done

This still breaks for files that contain trailing newlines (as they will be absorbed by the a=$(...) subshell. If you really want a foolproof method (and you should!), with a recent version of Bash (Bash≥4.0) that supports the ,, parameter expansion here's the ultimate solution:

find . -name '*.*' -print0 | while IFS= read -r -d '' f
do
base=${f%.*}
ext=${f##*.}
a=$base.${ext,,}
[ "$a" != "$f" ] && mv -- "$f" "$a"
done

Back to the original solution

Or in one find go (back to the original solution with some fixes that makes it really foolproof):

find . -name '*.*' -type f -exec bash -c 'base=${0%.*} ext=${0##*.} a=$base.${ext,,}; [ "$a" != "$0" ] && mv -- "$0" "$a"' {} \;

I added -type f so that only regular files are renamed. Without this, you could still have problems if directory names are renamed before file names. If you also want to rename directories (and links, pipes, etc.) you should use -depth:

find . -depth -name '*.*' -type f -exec bash -c 'base=${0%.*} ext=${0##*.} a=$base.${ext,,}; [ "$a" != "$0" ] && mv -- "$0" "$a"' {} \;

so that find performs a depth-first search.

You may argue that it's not efficient to spawn a bash process for each file found. That's correct, and the previous loop version would then be better.

Convert folder and file names to camel case

You can use the regular expression aptitude to deal with upper and lower case translations, regarding your current local collation (LC_ALL, check with the locale command).

If your filename's "words" are separated with a space and are all in lower case, you can use a simple shell script like this :

#!/bin/sh
while read -r FILENAME ; do
NEWNAME="`echo \"${FILENAME}\" | sed 's/ *\([^ ]\)/\u\1/g'`"
if [ ! "${NEWNAME}" ] ; then
NEWNAME="${FILENAME}";
fi
if [ "${FILENAME}" = "${NEWNAME}" ]; then
printf "No change : %s\\n" "${FILENAME}" >&2;
else
if [ -e "${NEWNAME}" ] ; then
printf "Already changed : %s => %s\\n" "${FILENAME}" "${NEWNAME}" >&2;
else
echo "mv \"${FILENAME}\" \"${NEWNAME}\"";
fi
fi
done

Remove the echo on echo "mv \"${FILENAME}\" \"${NEWNAME}\""; to do the mv.

Note that it should work fine with accented letters or any unicode letter having lower and upper code.

The script takes the file list to operate from stdin, so to use it "as is", you can use something like the following examples :

  • find . -type 'f' | theScript.sh

    For a whole tree of files.
    For folders, you'll have to operate them separately. List them and sort them in a descending order.

  • ls -1 | theScript.sh

    For files in the current folder.

If your files may have all or partial upper cases at start and you look to force them entirely to camel case, you can change the line :

  NEWNAME="`echo \"${FILENAME}\" | sed 's/  *\([^ ]\)/\u\1/g'`"

With:

  NEWNAME="\`echo \"${FILENAME}\" | sed 's/\(.*\)/\l\1/;s/  *\([^ ]\)/\u\1/g'\`"

PHP: rename all files to lower case in a directory recursively

You can use the SPL's RecursiveDirectoryIterator for that.

<?php
$path = realpath('your/path/here');

$di = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::LEAVES_ONLY
);

foreach($di as $name => $fio) {
$newname = $fio->getPath() . DIRECTORY_SEPARATOR . strtolower( $fio->getFilename() );
echo $newname, "\r\n";
//rename($name, $newname); - first check the output, then remove the comment...
}


Related Topics



Leave a reply



Submit