Here is such script:
#!/bin/bash
# The destination where the new directory structure will be created
DEST="/tmp/new-order-pictures/"
MONTHS=('Jan' 'Feb' 'Mar' 'Apr' 'May' 'Jun' 'Jul' 'Aug' 'Sep' 'Oct' 'Nov' 'Dec')
# Walk through the first level directories, located in the current directory and go inside
for year in */
do
cd "$year"
# Walk through the months of the year
for month in "${MONTHS[@]}"
do
# Walk through the second level directories
for dir in */
do
# If we have coincidence between the name of the directory and the month
# go inside, make a new destination directory; ignore character cases^^
if [[ ${dir^^} =~ ${month^^} ]]
then
cd "$dir"
dest="${DEST}${year}${month}"
mkdir -p "$dest"
find . -type f | while IFS= read -r item
do
# Copy the files to the new destination and
# add the file's md5sum to its name to prevent files lose
filename=$(basename -- "$item")
extn="${filename##*.}"
name="${filename%.*}"
cp "$item" "${dest}/${name}-$(md5sum "$item" | cut -f1 -d' ').${extn}"
done
cd ..
fi
done
done
cd ..
done
The script should be executed in the first level directory where your images are located. You should tweak the destination directory - DEST="/tmp/new-order-pictures/"
. This version of the script relies that all files are in directories that contain the name of a month in one way or another. Example of usage:
user@host:~/Pictures$ tree .
.
├── 2013
│ ├── January 17, 2013
│ │ ├── Image1.jpg
│ │ └── Image 3.jpg
│ ├── January 24, 2013
│ │ └── Image2.jpg
│ ├── January 25, 2013
│ │ └── Image 3.jpg
│ ├── June 22, 2013
│ │ └── image1.jpg
│ ├── May 4, 2013
│ │ └── Image1.jpg
│ └── May 5, 2013
│ ├── Image1.jpg
│ └── Image 2.jpg
└── 2014
├── January 17, 2014
│ ├── Image1.jpg
│ └── Image 3.jpg
├── January 24, 2014
│ └── Image2.jpg
├── January 25, 2014
│ └── Image 3.jpg
└── May 5
├── Image1.jpg
└── Image 2.jpg
12 directories, 14 files
user@host:~/Pictures$ order.sh
user@host:~/Pictures$ tree /tmp/new-order-pictures/
/tmp/new-order-pictures/
├── 2013
│ ├── Jan
│ │ ├── Image1-7b71d9fdfe5b15a2d1a4968c195f93ae.jpg
│ │ ├── Image2-cbf4d36ff84e7ec24c05f8181236e6b8.jpg
│ │ ├── Image 3-0bca5188fd3f3eb470533fdaf0630633.jpg
│ │ └── Image 3-6a83880cae1aa57e19a7c45de7759e68.jpg
│ ├── Jun
│ │ └── image1-adb3bf995f1a25d008f758a7266d7be5.jpg
│ └── May
│ ├── Image1-511d541b35fcb38af8ada18d7961268c.jpg
│ ├── Image1-a66c5863e6986605cb2ca6d622ae72a0.jpg
│ └── Image 2-c34ffc32ce5d3901e1ad89b9fd15a877.jpg
└── 2014
├── Jan
│ ├── Image1-7b71d9fdfe5b15a2d1a4968c195f93ae.jpg
│ ├── Image2-cbf4d36ff84e7ec24c05f8181236e6b8.jpg
│ ├── Image 3-0bca5188fd3f3eb470533fdaf0630633.jpg
│ └── Image 3-6a83880cae1aa57e19a7c45de7759e68.jpg
└── May
├── Image1-511d541b35fcb38af8ada18d7961268c.jpg
└── Image 2-c34ffc32ce5d3901e1ad89b9fd15a877.jpg
7 directories, 14 files
In my case the script is named order.sh
and it is located in ~/bin
, thus I can use it as shell command. In the example you can see the directory structure is changed but the number of files is 14 in both structures.
Here is another version of the script that use mv
instead of cp
and will deal also with the files which are not in directories that contain the name of a month. Before running this script it is a good idea to create a backup copy of the original directory structure.
#!/bin/bash
# The destination where the new directory structure will be created
DEST="/tmp/new-order-pictures/"
MONTHS=('Jan' 'Feb' 'Mar' 'Apr' 'May' 'Jun' 'Jul' 'Aug' 'Sep' 'Oct' 'Nov' 'Dec')
# Walk through the first level directories, located in the current directory and go inside
for year in */
do
cd "$year"
# Walk through the months of the year
for month in "${MONTHS[@]}"
do
# Walk through the second level directories
for dir in */
do
# If we have coincidence between the name of the directory and the month
# go inside, make a new destination directory; ignore character cases^^
if [[ ${dir^^} =~ ${month^^} ]]
then
cd "$dir"
dest="${DEST}${year}${month}"
mkdir -p "$dest"
while IFS= read -r item
do
# Copy the files to the new destination and
# add the file's md5sum to its name to prevent files lose
filename=$(basename -- "$item")
extn="${filename##*.}"
name="${filename%.*}"
mv "$item" "${dest}/${name}-$(md5sum "$item" | cut -f1 -d' ').${extn}"
done < <(find . -type f)
cd ..
fi
done
done
# Dial with the rest of the files for that $year
dest="${DEST}${year}other"
while IFS= read -r item
do
mkdir -p "$dest"
filename=$(basename -- "$item")
extn="${filename##*.}"
name="${filename%.*}"
mv "$item" "${dest}/${name}-$(md5sum "$item" | cut -f1 -d' ').${extn}"
done < <(find . -type f)
cd ..
done
Example of usage:
user@host:~/Pictures$ tree .
.
├── 2013
│ ├── January 17, 2013
│ │ ├── Image1.jpg
│ │ ├── Image 3.jpg
│ │ └── video 7.mpg
│ ├── January 25, 2013
│ │ └── Image 3.jpg
│ ├── June 22, 2013
│ │ └── image1.jpg
│ └── May 5, 2013
│ ├── Image1.jpg
│ └── Image 2.jpg
└── 2014
├── Apr 7
│ ├── Image1.jpg
│ └── Image 2.jpg
├── Image 2.jpg
├── January 11, 2014
│ ├── Image1.jpg
│ └── Image 3.jpg
├── some other name
│ └── some other name file inside.jpg
├── some other name file inside.jpg
└── video 1.avi
9 directories, 15 files
user@host:~/Pictures$ order.sh
user@host:~/Pictures$ tree /tmp/new-order-pictures/
/tmp/new-order-pictures/
├── 2013
│ ├── Jan
│ │ ├── Image1-7b71d9fdfe5b15a2d1a4968c195f93ae.jpg
│ │ ├── Image 3-0bca5188fd3f3eb470533fdaf0630633.jpg
│ │ ├── Image 3-6a83880cae1aa57e19a7c45de7759e68.jpg
│ │ └── video 7-86764d9565469adfb22c8ef4f0b9c04f.mpg
│ ├── Jun
│ │ └── image1-adb3bf995f1a25d008f758a7266d7be5.jpg
│ └── May
│ ├── Image1-511d541b35fcb38af8ada18d7961268c.jpg
│ └── Image 2-c34ffc32ce5d3901e1ad89b9fd15a877.jpg
└── 2014
├── Apr
│ ├── Image1-3c19da25e0e56ef0fc752a9e4f75b190.jpg
│ └── Image 2-dcc35e86de393a014ac62e8c4390c7e6.jpg
├── Jan
│ ├── Image1-ae34289b0bc5258f286165745ff3c258.jpg
│ └── Image 3-1724adf2dfcc1d4a0dc50cb38ad2c510.jpg
└── other
├── Image 2-eff5208f7eee6a536e48f9982b918dfb.jpg
├── some other name file inside-7d0a68e0b4e9cc3928744cb83f4d1136.jpg
├── some other name file inside-c2dd637e94a9025c3e1004d66f59539c.jpg
└── video 1-c277d93a2427bedf3f0b8ae07427edb9.avi
8 directories, 15 files
After that you can go inside the destination directory and use the rename
command within for
loop to deal with the long names:
# For each directory on the second level
for dir in */*
do
cd "$dir"
rename 's/^.*(\.[0-9a-zA-Z]+)$/our $i; sprintf("Image-%03d$1", 1+$i++)/e' *
cd ..
cd ..
done
Example:
user@host:~/Pictures$ cd /tmp/new-order-pictures/
user@host:/tmp/new-order-pictures$ for dir in */*; do cd "$dir"; rename 's/^.*(\.[0-9a-zA-Z]+)$/our $i; sprintf("Image-%03d$1", 1+$i++)/e' *; cd ..; cd ..; done
user@host:/tmp/new-order-pictures$ tree .
.
├── 2013
│ ├── Jan
│ │ ├── Image-001.jpg
│ │ ├── Image-002.jpg
│ │ ├── Image-003.jpg
│ │ └── Image-004.mpg
│ ├── Jun
│ │ └── Image-001.jpg
│ └── May
│ ├── Image-001.jpg
│ └── Image-002.jpg
└── 2014
├── Apr
│ ├── Image-001.jpg
│ └── Image-002.jpg
├── Jan
│ ├── Image-001.jpg
│ └── Image-002.jpg
└── other
├── Image-001.jpg
├── Image-002.jpg
├── Image-003.jpg
└── Image-004.avi
8 directories, 15 files
Or you can change (\.[0-9a-zA-Z]+)
with (\.jpg)
, then on next iteration with (\.mpg)
(respectively Image-
with Video-
), etc. References about this usage of rename
:
exiftool '-FileName<DateTimeOriginal' -d %Y/%m-%B/%f%%-c.%%e . -r
-> it's almost perfect, except for some .mov files which do not have exif data – Charles Green Jan 17 '19 at 00:28