以下は単純な Bash コマンドラインです。
grep -li 'regex' "filename with spaces" "filename"
問題ありません。以下も問題なく動作します:
grep -li 'regex' $(<listOfFiles.txt)
listOfFiles.txt
grep するファイル名のリストが 1 行に 1 つずつ含まれます。
問題は、 にスペースが埋め込まれたファイル名が含まれている場合に発生します。私が試したすべてのケース (以下を参照) で、Bash はファイル名をスペースで分割します。そのため、たとえば、のような名前を含むlistOfFiles.txt
の行では、各部分 ( 、、 )に対して grep を実行しようとします。listOfFiles.txt
./this is a file.xml
./this
is
a
file.xml
私は比較的上級の Bash ユーザーだと思っていましたが、これを機能させるための簡単な魔法の呪文を見つけることができません。私が試したことは次のとおりです。
grep -li 'regex' `cat listOfFiles.txt`
上記のように失敗します (実際にこれが機能するとは思っていませんでした)。そのため、各ファイル名を引用符で囲むことにしました。
grep -li 'regex' `sed -e 's/.*/"&"/' listOfFiles.txt`
Bashは引用符をファイル名の一部として解釈し、各ファイルに対して「そのようなファイルまたはディレクトリはありません」と表示します(そしてまだファイル名を空白で分割します)
for i in $(<listOfFiles.txt); do grep -li 'regex' "$i"; done
これは、元の試みと同様に失敗し (つまり、引用符が無視されているかのように動作します)、1 回の呼び出しですべてのファイルを処理するのではなく、ファイルごとに 1 つの「grep」プロセスを起動する必要があるため、非常に遅くなります。
以下は機能しますが、正規表現にシェルのメタ文字が含まれている場合は、慎重に二重エスケープを行う必要があります。
eval grep -li 'regex' `sed -e 's/.*/"&"/' listOfFiles.txt`
スペースを含むファイル名を正しく処理できるようにコマンド ラインを構築する唯一の方法は、これですか?
ベストアンサー1
これを試して:
(IFS=$'\n'; grep -li 'regex' $(<listOfFiles.txt))
IFS
は内部フィールド区切り文字です。 に設定すると$'\n'
、Bash は改行文字を使用してファイル名を区切ります。デフォルト値は で$' \t\n'
、 を使用して印刷できますcat -etv <<<"$IFS"
。
スクリプトを括弧で囲むとサブシェルが開始され、括弧内のコマンドのみがカスタムIFS
値の影響を受けるようになります。