我已经为此绞尽脑汁一段时间了,但我真的不是一位优秀的剧本作家。抱歉...
我正在运行 Ubuntu/gnome 18.10,并且从我妻子的 Mac 导出了大量图片。目录结构如下:
year1
(login dir name with spaces) - Month
Image names
year2
...
例如:
2013
May 4, 2013
Image1.jpg
Image2.jpg
May 5, 2013
Image 1.jpg
Image 3.jpg
June 22, 2013
我想要的是:
2013
January
All the "january" images...
February
All the...
我可以轻松创建目录mkdir {January..December}
。但我搞不清楚如何遍历丑陋的目录树(从 Mac 导出)、移动图像,然后删除丑陋的目录。
答案1
有一个应用程序可以在单个命令行中移动和重命名文件 -exiftool
sudo apt install libimage-exiftool-perl
就我而言,使用的具体命令行是
exiftool '-FileName<DateTimeOriginal' -d <path-to-output-dir>/%Y/%m-%B/%Y%m%d_%H%M%S%%-c.%%e . -r
或者
exiftool '-FileName<CreateDate' -d <path-to-output-dir>/%Y/%m-%B/%Y%m%d_%H%M%S%%-c.%%e . -r
取决于图像中存在的标签。如果请求的标签不存在,应用程序会发出警告并且不会移动该文件,而是继续处理。此应用程序还可以通过在文件名末尾附加数字来处理具有相同日期/时间的多幅图像。
我确实有几张没有 exif 数据的图像,但我能够使用命令将 exif 数据添加到图像中
exiftool -createdate='2011:12:04 12:00:00' * -overwrite_original
举个例子,我将一些图像放在目录 ~/aa/test1 中,然后运行该工具,将输出放在 ~/aa/test2 中。结果如下:
chick@dad:~/aa$ tree .
.
├── test1
│ ├── DSC00018.JPG
│ ├── DSC00022.JPG
│ ├── DSC00024.JPG
│ ├── DSC00025.JPG
│ ├── DSC00026.JPG
│ ├── DSC00028.JPG
│ ├── DSC00031.JPG
│ ├── DSC00033.JPG
│ └── Thumbs.db
└── test2
└── 2000
└── 12-December
├── 20001222_185523.JPG
├── 20001222_200726.JPG
├── 20001222_200819.JPG
├── 20001222_201205.JPG
├── 20001222_201223.JPG
├── 20001222_210536.JPG
├── 20001222_211858.JPG
└── 20001222_215950.JPG
答案2
以下是此类脚本:
#!/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
该脚本应在图像所在的第一级目录中执行。您应该调整目标目录 - DEST="/tmp/new-order-pictures/"
。此版本的脚本依赖于所有文件都位于以某种方式包含月份名称的目录中。使用示例:
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
在我的例子中,脚本被命名order.sh
并且位于 中~/bin
,因此我可以将其用作 shell 命令。在示例中,您可以看到目录结构已更改,但两个结构中的文件数均为 14。
这是另一个版本的脚本,它使用mv
代替cp
,还将处理不包含在月份名称的目录中的文件。在运行此脚本之前,最好创建原始目录结构的备份副本。
#!/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
使用示例:
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
之后,您可以进入目标目录并使用循环rename
内的命令for
来处理长名称:
# 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
例子:
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
或者您可以(\.[0-9a-zA-Z]+)
使用进行更改(\.jpg)
,然后在下一次迭代中使用(\.mpg)
(分别Image-
使用Video-
)等等。有关 用法的参考rename
: