2016-11-20 30 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