A common way of batch renaming filenames on the command-line, is to use the "mv" & "sed" commands with a "for loop", or using "find" with the exec option.
Here I'll show a couple of examples utilizing both options.
Here is a typical rename example converting uppercase "JPG" filename extensions to lowercase "jpeg" using "mv", "sed" and command substitution.
Create test folder and populate it with a couple of test files.
$ mkdir test_folder && cd test_folder/
$ touch {1..3}.JPG
$ ls -1
1.JPG
2.JPG
3.JPG
Batch rename the files with "JPG" filename extension to "jpeg" filename extension, using sed.
$ for i in *.JPG; do mv "$i" "$(echo "$i" | sed 's/^\(.*\)\.JPG$/\1\.jpeg/')"; done
$ ls -1
1.jpeg
2.jpeg
3.jpeg
For a more elegant and faster solution using Bash parameter expansion/substitution.
$ for i in *.jpeg; do mv "$i" "${i%.jpeg}.jpg"; done
$ ls -1
1.jpg
2.jpg
3.jpg
This works well for a single folder containing files we want to rename.
If we have several nested folders with files we want to rename, using the find command and its exec option is a good choice.
This time we'll add another step and move every file we rename into a folder called "jpeg_folder"
Let's clear out our test folder, create subfolders and populate these with test files.
$ rm *
$ mkdir -p Subfolder.{1..5}
$ ls -1
Subfolder.1
Subfolder.2
Subfolder.3
Subfolder.4
Subfolder.5
Populate the folders with unique filenames and create the "jpeg_folder"
$ COUNT=1 ; for i in $(ls -1) ; do touch ./$i/$COUNT.{1..5}.JPG && ((COUNT++));done
$ mkdir jpeg_folder
That gives us the the following test scenario to work with
$ ls -1R
Subfolder.1
Subfolder.2
Subfolder.3
Subfolder.4
Subfolder.5
jpeg_folder
./Subfolder.1:
1.1.JPG
1.2.JPG
1.3.JPG
1.4.JPG
1.5.JPG
./Subfolder.2:
2.1.JPG
2.2.JPG
2.3.JPG
2.4.JPG
2.5.JPG
./Subfolder.3:
3.1.JPG
3.2.JPG
3.3.JPG
3.4.JPG
3.5.JPG
./Subfolder.4:
4.1.JPG
4.2.JPG
4.3.JPG
4.4.JPG
4.5.JPG
./Subfolder.5:
5.1.JPG
5.2.JPG
5.3.JPG
5.4.JPG
5.5.JPG
./jpeg_folder:
Let's use the "find" command to recursively find all files with a ".JPG" file extension and rename them with a ".jpeg" file extension, while also moving them into the "jpeg_folder"
$ find * -name "*.JPG" -exec sh -c 'mv "$0" "jpeg_folder/$(basename "${0%.JPG}.jpeg")"' {} \;
$ ls -1R
Subfolder.1
Subfolder.2
Subfolder.3
Subfolder.4
Subfolder.5
jpeg_folder
./Subfolder.1:
./Subfolder.2:
./Subfolder.3:
./Subfolder.4:
./Subfolder.5:
./jpeg_folder:
1.1.jpeg
1.2.jpeg
1.3.jpeg
1.4.jpeg
1.5.jpeg
2.1.jpeg
2.2.jpeg
2.3.jpeg
2.4.jpeg
2.5.jpeg
3.1.jpeg
3.2.jpeg
3.3.jpeg
3.4.jpeg
3.5.jpeg
4.1.jpeg
4.2.jpeg
4.3.jpeg
4.4.jpeg
4.5.jpeg
5.1.jpeg
5.2.jpeg
5.3.jpeg
5.4.jpeg
5.5.jpeg
As you can see from the previous example, the "find" command can be a very effective tool when paired with a bit Bash command substitution and parameter expansion/substitution.
Batch Renaming Files With Different Date Formats
That brings us to files containing different date formats in the filename.
We usually have two common formats, depending on which side of the Atlantic we're on.
Below are those, formatted with the "date" command
So for the "13th of March 2015":
# MDY date format (Month, Day, Year)
$ date +"%m-%d-%Y"
03-13-2015
# DMY date format (Day, Month, Year)
$ date +"%d-%m-%Y"
13-03-2015
Let's convert files with either of these two date formats to your choice of format.
Again let's clear our test folder and populate it with a few test files in which the MDY date format is included in the filename.
$ rm -rf *
$ touch somefilename-03-{13..15}-2015.txt
$ ls -1
somefilename-03-13-2015.txt
somefilename-03-14-2015.txt
somefilename-03-15-2015.txt
Let's convert those files to DMY format using sed in a "for loop"
$ for i in *.txt; do mv "$i" "$(echo $i|sed -E 's/(somefilename)\-([0-9]{2})\-([0-9]{2})\-([0-9]{4})(\.txt)/\1-\3-\2-\4\5/')"; done
$ ls -1
somefilename-13-03-2015.txt
somefilename-14-03-2015.txt
somefilename-15-03-2015.txt
For a faster version, converting it back to MDY format without the use of command substitution, sed or "piping", using Bash regular expressions.
$ for i in *.txt; do if [[ ${i} =~ (somefilename)-([0-9]{2})-([0-9]{2})-([0-9]{4})(\.txt) ]] ; then mv "$i" "${BASH_REMATCH[1]}-${BASH_REMATCH[3]}-${BASH_REMATCH[2]}-${BASH_REMATCH[4]}${BASH_REMATCH[5]}"; fi; done
$ ls -1
ls -1
somefilename-03-13-2015.txt
somefilename-03-14-2015.txt
somefilename-03-15-2015.txt
We can then convert back and forth between either format by running the same command again.
$ for i in *.txt; do if [[ ${i} =~ (somefilename)-([0-9]{2})-([0-9]{2})-([0-9]{4})(\.txt) ]] ; then mv "$i" "${BASH_REMATCH[1]}-${BASH_REMATCH[3]}-${BASH_REMATCH[2]}-${BASH_REMATCH[4]}${BASH_REMATCH[5]}"; fi; done
$ ls -1
somefilename-13-03-2015.txt
somefilename-14-03-2015.txt
somefilename-15-03-2015.txt
Voila! Hope you enjoyed it!
Lars Bjaerris