リストされたディレクトリ内のスペースを維持しながら、/foo
内のすべてのファイルをエコーしようとしています。現在、"bar1 bar2"
というタイトルのディレクトリは、すべて新しい行に/path/to/foo/bar1/
、次に/bar2
、次にfile.txt
としてエコーアウトされます。 /path/to/foo/bar1 bar2/file.txt
または/path/to/foo/bar1\ bar2/file.txt
をエコーするために必要です。
for file in $(find /path/to/foo/ -type f); do
if [[ ... ]]; then
echo "${file}"
fi
done
また試した:
for file in $(find /path/to/foo/ -type f | sed 's/ /\ /g'); do
if [[ ... ]]; then
echo "${file}"
echo "$file" # variations i've tried
echo $file # variations i've tried
echo ${file}
otherCommand "${file}"
fi
done
問題は_$file
_ではなく、$(find…)
の使用法にあります。
通常の変数と$(…)
プロセス置換はどちらも、まったく同じ種類の単語分割の対象になります。 $(find…)
を二重引用符で囲むと、すべての出力を含むsingle Wordが得られます。そうしないと、空白で分割されます– not改行またはおそらく予想したその他の魔法の境界だけです。
上記の重要な部分は、変数を展開するときにバックスラッシュエスケープがnot処理されることです。スペースで分割されているだけで、それだけです。
(言い換えると、_$file
_を引用しても、そもそも正しい値がなかったため、役に立ちませんでした!)
すべてのファイルを再帰的に処理する場合、オプションは次のとおりです。
別の方法でfind
からの出力を読み取ります。
_find … -print | while read -r file; do
echo "Got $file"
done
_
(補足:ファイル名には技術的に改行も含まれる場合があるため、まれに、それを防ぐことができます。
_find … -print0 | while read -r -d "" file; do
echo "Got $file"
done
_
少量のファイルの場合は、bashの拡張ワイルドカードを使用します。
_shopt -s globstar
for file in /path/to/foo/**; do
echo "Got $file"
done
_
ディレクトリが大きい場合、_find | while read
_の利点は、ストリーミングされることです。スクリプトは、結果が来たときに処理します。一方、$(find)
とワイルドカードの両方が最初にすべてをメモリに収集し、次に(おそらく大規模な)結果を返す必要があります。
一方、パイプを使用すると、全体while
ループ(read
コマンドだけでなく)に影響するため、実行する場合は何でもキーボード入力を読み取りたい場合は、元のstdinを手動で提供する必要があります。 _vim "$file" < /dev/tty
_。