web-dev-qa-db-ja.com

名前にスペースが含まれるファイルをパイプで使用する

playという名前のフォルダがあります。このフォルダにはdamn file(スペースあり)。 findを使用して出力をtarにパイプすると、次のようになります。

find play/ -name 'damn*' | tar cf archive.tar -T -

それは完璧に動作します。なぜこれが機能するのかfindの出力には、tarに問題を引き起こすはずのスペースが含まれています。このコマンドを使用すると:

tar cf archive.tar $(find play/ -name 'damn*')

bashはこれらのエラーを示しています:

tar: play/damn: Cannot stat: No such file or directory
tar: file: Cannot stat: No such file or directory
tar: Exiting with failure status due to previous errors

よくわかりません。最初の例が機能するのはなぜですか?

4
Majid Azimi

2番目の例では、改行はシェルによって削除されます。シェルは、コマンド置換の出力でワード分割を行います。改行はデフォルトでIFSに含まれているため、フィールド自体の一部としてではなく、フィールド区切り文字として扱われます。最初の例では、入力はシェルではなくパイプからのものであるため、シェルはワード分割を実行できません。

コマンド置換("$(find ... )")を二重に引用すると、単語の分割が行われなくなりますが、コマンド置換内のfindは、ほとんどの場合badのアイデアなので、実行しないでください。それ。安全性を最大限に高めるために、UnixツールのGNUバージョンにアクセスできる場合は常に、null区切り文字オ​​プションを使用する必要があります。

find dir/ -name '...' -print0 | tar cf foo.tar --null --no-recursion -T -
8
jw013

_find play/ -name 'damn*'_は、ファイル名のリストを1行に1つずつ生成します。 _play/damn file_が唯一の一致するファイルである場合、それは_echo 'play/damn file'_と同等です。

Tarの _-T_オプション ファイル名は改行で区切られる必要があります。その他の空白はファイル名の一部と見なされます。これが、最初の例が機能する理由です。

$(...) を使用すると、コマンドの出力はシェルによって 空白で分割 になり、各Wordはtar。したがって、_play/damn_とfileは2つの引数になり、どちらも既存のファイルではありません。

4
cjm