如果问题标题不够丰富,我很抱歉。请随意提出更好的变体。
我想执行以下任务: 在一个目录中,我有许多文件是JPEG格式的照片。我想从EXIF中提取拍摄照片的日期,为每个日期创建一个新目录,并将文件移动到相关目录。
(EXIF日期和时间的格式为union
,我希望将目录名称格式化为YYYY:MM:DD hh:mm:ss
,这就是我使用sed的原因)
我知道如何分别执行这些任务,但未能将它们组合在一起。我花了一些时间研究如何使用YYYY-MM-DD
find
或-exec
来执行命令,但仍然无法理解如何正确链接所有内容。
最后,我能够使用两个命令完成我的任务:
xargs
但我不喜欢重复,我不喜欢find . -name '*.jpg' -exec sh -c "identify -format %[exif:DateTimeOriginal] {}
| sed 's/ [0-9:]*//; s/:/-/g' | xargs mkdir -p" \;
find . -name '*.jpg' -exec sh -c "identify -format %[exif:DateTimeOriginal] {}
| sed 's/ [0-9:]*//; s/:/-/g; s/$/\//' | xargs mv {}" \;
。有没有正确的方法在一行中执行此操作而不使用-exec sh -c
?
答案 0 :(得分:5)
不是专注于单行,更好的解决方案是将逻辑放入脚本中,以便于执行和测试。将其放在名为movetodate.sh
的文件中:
#!/usr/bin/env bash
# This script takes one or more image file paths
set -e
set -o pipefail
for path in "$@"; do
date=$(identify -format %[exif:DateTimeOriginal] | sed 's/ [0-9:]*//; s/:/-/g')
dest=$(dirname "$path")/$date
mkdir -p "$dest"
mv "$path" "$dest"
done
然后,调用它:
find . -name '*.jpg' -exec ./movetodate.sh {} +
答案 1 :(得分:2)
使用exiftool轻松完成:
exiftool "-Directory<DateTimeOriginal" -d %Y-%m-%d *.jpg
例如,该命令会转换如下布局:
.
├── a.jpg (2013:10:17 10:01:00)
└── b.jpg (2012:08:07 16:11:15)
到此:
.
├── 2012-08-07
│ └── b.jpg
└── 2013-10-17
└── a.jpg
如果您仍想使用identify
,可以按如下方式重写命令:
script=$(cat <<'SCRIPT'
d=$(
d=$(identify -format "%[exif:DateTimeOriginal]" "$0" 2>/dev/null) || exit $?
d=${d:0:10}
printf '%s/%s' "$(dirname "$0")" "${d//:/-}"
) || exit $?
mkdir -p "$d" && mv -v "$0" "$d"
SCRIPT
)
find "$dir" -name '*.jpg' -exec bash -c "$script" {} \;
请注意在脚本中使用$0
变量。我们将{}
占位符作为第一个参数传递给脚本。
在for file in "$@"
循环的帮助下,可以轻松转换脚本以接受多个参数(路径)。在这种情况下,\;
字符应替换为+
。但是,如果您有大量超过$(getconf ARG_MAX)
限制的文件,则需要xargs
或逐个处理文件,如上面的脚本所示。对exiftool
命令应用相同的注意事项。
答案 2 :(得分:0)
使用并行,您不需要脚本,而是执行:
doit() {
path="$1"
date=$(identify -format %[exif:DateTimeOriginal] | sed 's/ [0-9:]*//; s/:/-/g')
dest=$(dirname "$path")/$date
mkdir -p "$dest"
mv "$path" "$dest"
}
export -f doit
find . -name '*.jpg' | parallel doit