シェルスクリプトでファイル名を適切に解析することは常に難しいため、理想的にはまったくそうしないでください(スペースを修正すると、他の埋め込み文字、特に改行で問題が発生します)。これは、BashPitfalls ページの最初のエントリとしてもリストされています。
そうは言っても、あなたが望むことをほとんど行う方法があります:
oIFS=$IFS
IFS=$'\n'
find . -name '*.txt' | while read -r i; do
# use "$i" with whatever you're doing
done
IFS=$oIFS
$i
も引用することを忘れないでください それを使用するときは、他のものが後でスペースを解釈するのを避けるためです。 $IFS
を設定することも忘れないでください そうしないと、後で当惑するようなエラーが発生するためです。
これには、もう 1 つの注意事項があります。while
内で何が起こるかです。 使用しているシェルによっては、ループがサブシェルで発生する可能性があるため、変数の設定が保持されない場合があります。 for
ループバージョンはそれを回避しますが、 $IFS
を適用してもその代償があります find
の場合、問題が発生します。 返されるファイルが多すぎます。
ある時点で、これらすべての正しい修正は、シェルではなく Perl や Python などの言語で行うことになります.
find -print0
を使用 xargs -0
にパイプします。 、または独自の小さな C プログラムを作成し、それを小さな C プログラムにパイプします。これが -print0
です と -0
のために発明されました。
シェル スクリプトは、スペースを含むファイル名を処理する最適な方法ではありません。実行できますが、扱いにくくなります。
「内部フィールドセパレータ」(IFS
)を設定できます ) ループ引数分割のためのスペース以外の何かに、例えば
ORIGIFS=${IFS}
NL='
'
IFS=${NL}
for i in $(find . -name '*.txt'); do
IFS=${ORIGIFS}
#do stuff
done
IFS=${ORIGIFS}
IFS
をリセットしました find で使用した後、主に見栄えが良いためだと思います。改行に設定しても問題はありませんが、これは「よりクリーン」だと思います。
find
からの出力で何をしたいかによって、別の方法 、 -exec
を直接使用することです find
で コマンド、または -print0
を使用 xargs -0
にパイプします。 .最初のケース find
ファイル名のエスケープを処理します。 -print0
で ケース、find
その出力を null 区切り記号で出力し、次に xargs
を出力します これで分かれます。ファイル名にその文字を含めることはできないため (私が知っていること)、これも常に安全です。これは単純な場合に最も役立ちます。通常、完全な for
の代わりにはなりません。 ループ。