2016-11-20 33 views
3

如果问题标题不够丰富,我很抱歉。请随时提出一个更好的变体。find,xargs:为每个文件执行命令链

我想执行以下任务: 在一个目录中,我有一些文件是JPEG格式的照片。我想从EXIF中提取这些照片拍摄的日期,为每个日期创建一个新目录,并将文件移动到相关目录。

(EXIF日期和时间的格式为YYYY:MM:DD hh:mm:ss,和我想要的目录名被格式化为YYYY-MM-DD,这就是为什么我使用SED)

我那种知道如何分别执行各自的那些任务,但没能把他们放在一起。我花了一些时间研究如何使用find-execxargs执行命令,但仍未能理解如何正确链接所有内容。

最后我是能够使用两个命令来完成我的任务:

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。有没有正确的方法来做到这一点,而不使用-exec sh -c

回答

5

更好的解决方案是将逻辑放入脚本中,使其易于执行和测试,而不是专注于单行程。在一个名为movetodate.sh文件将这个:

#!/usr/bin/env bash 

# This script takes one or more image file paths 

set -e 
set -o pipefail 

for path in "[email protected]"; 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 {} + 
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 "[email protected]"循环,脚本可以很容易地转换为接受多个参数(路径)。在这种情况下,\;字符应替换为+。但是,如果您有大量文件超过$(getconf ARG_MAX)的限制,则您将需要xargs,或者如上面的脚本中所示逐个处理文件。 exiftool命令也适用同样的考虑事项。

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