3

I need a oneliner to rename all files in a directory from

SomeThing.TXT
NOT A FILE.ogg
sensitive lalala.doc

to

Something.txt
Not A File.ogg
Sensitive Lalala.doc

In other words: first letters of words are capital case and everything else is lowercase. This is called Start case or initial caps. It is very close to "Title case". The file extension should be lower case.

Most existing questions seem to only deal with UPPERCASE.MKV or lowercase.mkv filenames, none seem to cover Capitalized Case.mkv (example).

All the common tools like pipes, sed, perl, grep and more can be used.

5
  • Which Linux are you using? Is it Debian-based?
    – terdon
    Jul 30, 2015 at 12:03
  • @terdon Arch Linux but let's keep it portable enough for that not to matter. :)
    – qubodup
    Jul 30, 2015 at 12:12
  • Just wondering what your rename is. Is it the perl one on Arch or the BSD one?
    – terdon
    Jul 30, 2015 at 12:13
  • The owning package for /usr/bin/rename is util-linux. perl-rename is a separate command with a package of the same name.
    – qubodup
    Jul 30, 2015 at 12:20
  • Yeah, many systems ship with the util-linux one as default. Well, if you have perl-rename, you can use my answer. On my Debian, it claims to warn before overwriting but doesn't actually do so. I also added a shell version that can avoid overwriting.
    – terdon
    Jul 30, 2015 at 12:33

4 Answers 4

3

If you have access to perl rename, (installed by default as rename on Debian-based systems, available as perl-rename on many others), you could run:

rename  's/.*/lc($&)/e; s/(^| )./uc($&)/ge' *

Explanation:

The rename program will run a perl expression on each of its input file names. Here, the first substitution operation (s///) will replace everything (.*) with itself ($& is whatever was matched) but lower cased (lc($&)). The second, will match every character that's after a space or at the beginning of the file name ((^| )) and replace it with its upper cased version (uc($&)).

Run with the -n flag to test without making any changes:

$ rename -n 's/.*/lc($&)/e; s/ ./uc($&)/ge' *
rename NOT A FILE.ogg not A File.ogg
rename sensitive lalala.doc sensitive Lalala.doc
rename SomeThing.TXT something.txt

You could also use a shell loop and perl:

for f in *; do 
    mv "$f" "$(perl -lpe 's/.*/lc($&)/e; s/(^| )./uc($&)/ge' <<<"$f")"
done

This is the same command as in the rename above, only we feed it each file in the directory and use command substitution to rename.

You could easily modify this to avoid overwriting existing files:

for f in *; do 
    target="$(perl -lpe 's/.*/lc($&)/e; s/(^| )./uc($&)/ge' <<<"$f")"; 
    [ -e "$target" ] && 
        echo "File \"$target\" exists, skipping \"$f\"" || 
        mv "$f" "$target"; 
done
1
  • The last script works really fine. Unfortunately on Ubuntu (LTS 14.04.4 LT) the first line proposed generates errors with name with spaces... (/usr/bin/rename symlink to /etc/alternatives/rename symlink to /usr/bin/prename ; perl file RCSfile: rename,v Revision: 4.1 ).
    – Hastur
    Apr 22, 2016 at 14:13
1

"De-capitalizing" answered here:

for i in *
do
  mv "$i" "$( echo $i | tr '[:upper:]' '[:lower:]')"
done

Capitalizing already answered here:

for i in *
do
  mv "$i" "$( echo $i | sed 's/[ ]*/\u&/g')"
done
2
  • Please don't post link-only answers. Even if the link is pointing to other sites on the SE network. Instead, copy the relevant information into your question or write an answer to this question, based on the information there.
    – terdon
    Jul 30, 2015 at 12:09
  • Please summarize the linked answer.
    – Hamed
    Jul 30, 2015 at 12:24
1

This works on Bash 3.2.57 for Mac OSX

Preview (doesn't change anything):

IFS=$'\n';FOLDER=new;for F in $(ls -1);do EXT="${F##*.}";NAME="${F%.*}";NEW=$(echo "$NAME"| perl -pe 's/[ _-]([A-z0-9])([^ _-]+)/ \U\1\L\2/g');echo "cp '$F' '$FOLDER/$NEW.$EXT'";done

If the preview looks good, you can use this to rename and cp into subfolder:

IFS=$'\n';FOLDER=new;[ -d $FOLDER ] || mkdir $FOLDER;for F in $(ls -1);do EXT="${F##*.}";NAME="${F%.*}";NEW=$(echo "$NAME"| perl -pe 's/[ _-]([A-z0-9])([^ _-]+)/ \U\1\L\2/g');cp -v "$F" "$FOLDER/$NEW.$EXT";done

Notes:

  • Will not change the file extension.
  • Should handle numbers correctly.
  • If you have other chars you want to be converted to spaces, just add them to the character class: [ _-]
  • Avoids conflicting names by making a copy of each file into a subfolder. This gives you an "undo" option. Another way to handle this would be to rename all files, while adding a prefix like _My New File Name.jpg, then rename all of those to versions without the _.
1
  • Unfortunately, this doesn't seem to rename the first character of a file name.
    – qubodup
    Jul 9, 2016 at 21:20
1

I came up with a quick solution in one-liner form:

for f in *; do mv -i "$f" "`echo $f | sed -e 's/\(.*\)/\L\1/' -e 's/\( .\)/\U\1/g' -e 's/\(^.\)/\U\1/g'`"; done

Or in readable (but marginally less comfortable to copy paste form):

for f in *; do 
    mv -i "$f" "`echo $f | 
     sed -e 's/\(.*\)/\L\1/' -e 's/\( .\)/\U\1/g' -e 's/\(^.\)/\U\1/g'`"; 
done

This command uses sed to mv each file to a file with the same name but in which all characters are first turned to lowercase, then each combination of space followed by any character is turned to uppercase, then the first character is turned uppercase.

This will ask before overwriting.

Remove -i if you want it automatically to overwrite.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .