複数のファイルで操作を実行する一般的な方法は次のとおりです。これについて私を非難しないでください。
for f in $(ls); do …
スペースやその他の奇妙な文字を含むファイルから安全にするには、次の簡単な方法に従ってください。
find . -type f -print0 | while IFS= read -r -d '' file; …
ここ-d ''
に図のようにASCII NUL設定の略語を示します-d $'\0'
。
ところで、なぜそうなのか?なぜ''
そして$'\0'
同じですか? Bash Cルートの空の文字列は常にnullで終わるからですか?
答え1
これman page of bash
内容は次のとおりです。
-d delim
The first character of delim is used to terminate the
input line, rather than newline.
文字列は通常 null で終わるため、空の文字列の最初の文字は null バイトです。 - 合理的だと思います。 :)
ソースは次のように書きました。
static unsigned char delim;
[...]
case 'd':
delim = *list_optarg;
break;
空の文字列の場合はdelim
null バイトです。
答え2
bashには互いに補完する2つの欠陥があります。
これを作成すると、$'\0'
内部的には空の文字列と同じように扱われます。たとえば、
$ a=$'\0'; echo ${#a}
0
bashは内部的にすべての文字列を次のように格納するためです。氏文字列、彼らnullで終了- NULLバイトは文字列の終わりを示します。 Bashは文字列を最初のnullバイト(文字列の一部ではない)まで自動的に切り捨てます。
# a=$'foo\0bar'; echo "$a"; echo ${#a}
foo
3
-d
組み込みオプションに文字列を引数として渡すと、read
bashは文字列の最初のバイトのみを調べます。しかし、実際に文字列が空でないことを確認するわけではありません。内部的には、空の文字列は、nullバイトのみを含む1要素バイト配列として表されます。したがって、bashは文字列の最初のバイトを読み取るのではなく、nullバイトを読み込みます。
その後、内部的に組み込み関数の背後にあるメカニズムは、区切りread
文字が見つかるまでバイト単位でnullバイトを処理し続けます。
他のシェルは異なる動作をします。たとえば、ash と ksh は、入力を読み取るときに null バイトを無視します。 ksh を使用してksh -d ""
改行文字が表示されるまで読みます。シェルは、バイナリデータではなくテキストとうまく機能するように設計されています。 Zshは例外です。 zsh は、任意のバイト (ヌルバイトを含む) を処理する文字列表現を使用し、$'\0'
長さが 1 の文字列です (ただし、read -d ''
奇妙にも同様に動作しますread -d $'\0'
)。