1

音楽ファイルを処理する bash スクリプトを作成しようとしています。これまでのスクリプトは次のとおりです。

#!/bin/bash

SAVEIFS=$IFS
IFS=printf"\n\0"

find `pwd` -iname "*.mp3" -o -iname "*.flac" | while read f
do
    echo "$f"
    $arr=($(f))
    exiftool "${arr[@]}"
done

IFS=$SAVEIFS

これは次の場合に失敗します。

[johnd:/tmp/tunes] 2 $ ./test.sh 
./test.sh: line 9: syntax error near unexpected token `$(f)'
./test.sh: line 9: `    $arr=($(f))'
[johnd:/tmp/tunes] 2 $ 

私は多くの異なる呪文を試しましたが、どれもうまくいきませんでした。肝心なのは、コマンドを呼び出そうとしているexiftoolことです。そのコマンドのパラメーターの 1 つは、スペースを含む可能性のあるファイル名です。$f上記では、ファイル名を配列に割り当ててその配列を に渡そうとしていますが、配列exiftoolの構築に問題があります。

当面の質問は、この配列をどのように構築するのですか? しかし、より深い問題は、bash スクリプト内から、スペースを含む可能性のあるパラメーターを使用して外部コマンドを呼び出すにはどうすればよいかということです。

4

2 に答える 2

5

実際には、call-with-possibly-space-contain-arguments 構文は正しくありました ( program "${args[@]}")。ただし、いくつかの問題がありました。

まず、$(foo) コマンドを実行します。変数の値が必要な場合は、$fooまたはを使用します${foo}

次に、配列に何かを追加する場合の構文はarray+=(value)(または、それが機能しない場合はarray=("${array[@]}" value)) です。

第三に、ファイル名は可能な限りで区切ってください。改行はすべて問題ありませんが、ファイル名には改行を含めることができます。\0

4 番目に、区切り文字として指定する空の文字列で使用できるreadスイッチを受け取ります。これにより、いじる必要がなくなります。-d''\0IFS

第 5 に、ループにパイプするときは注意しwhileてください。これにより、ループがサブシェルで実行され、ループ内の変数の割り当てが外部で有効になるのを防ぎます。ただし、これを回避する方法があります。パイピング ( command | while ... done) の代わりに、プロセス置換 ( while ... done < <(command)) を使用します。

第 6 に、プロセスの置換に注意してください。$(pwd)コマンドの引数として使用する必要はあり.ません。(または、本当に完全なパスが必要な場合は、pwd呼び出しを引用してみてください。)

tl;dr

改訂されたスクリプト:

while read -r -d '' f; do
    echo "$f" # For debugging?
    arr+=("$f")
done < <(find . -iname "*.mp3" -o -iname "*.flac" -print0)
exiftool "${arr[@]}"

別の方法

の全機能を活用find:

find . -iname "*.mp3" -o -iname "*.flac" -exec exiftool {} +
# Much shorter!

編集 1

exiftoolの出力を保存し、操作してからコピーする必要がありますか? これを試して:

while read -r -d '' f; do
    echo "$f" # For debugging?
    arr+=("$f")
done < <(find . -iname "*.mp3" -o -iname "*.flac" -print0)
# Warning: somewhat misleading syntax highlighting ahead
newfilename="$(exiftool "${arr[@]}")"
newfilename="$(manipulate "$newfilename")"
cp -- "$some_old_filename" "$newfilename"

おそらく最後のビットを変更する必要があります-私は を使用exiftoolしたことがないので、あなたが何を求めているのか(またはその方法)は正確にはわかりませんが、それは最初の一歩です.

于 2013-05-03T12:24:46.190 に答える
2

これは、bash だけで実行できます。

shopt -s globstar nullglob
a=( **/*.{mp3,flac} )
exiftool "${a[@]}"

これもおそらく機能します:exiftool **/*.{mp3,flac}

于 2013-05-03T13:37:07.790 に答える