Bashのファイルパスには、$'\0'
nullバイト(値が0のバイト)を除く任意の文字を含めることができるので、nullバイトを区切り文字として使用するのが最善です。たとえば、出力をfind
別のプログラムに送信する場合は、この-print0
オプション(find
このオプションがあるバージョンの場合)を使用することをお勧めします。
しかし、このような操作はうまくいきますが、(改行で区切られたファイルパスを印刷する - 心配しないでください。これは単なるデモであり、実際のスクリプトでは実際にこれを行いません):
find -print0 \
| while IFS= read -r -d $'\0' ; do echo "$REPLY" ; done
このようないいえ働く:
for file in * ; do echo -n "$file"$'\0' ; done \
| while IFS= read -r -d $'\0' ; do echo "$REPLY" ; done
for
-loop部分のみを使用しようとすると、すべてのファイル名が一緒に印刷されることがわかりました。いいえその間にはヌルバイトがあります。
なぜこれですか?どうなりますか?
答え1
Bashは内部的にヌルバイトで終わるCスタイルの文字列を使用します。つまり、Bash文字列(変数値やコマンド引数など)には、実際にはnullバイトを含めることはできません。たとえば、次のミニスクリプトは次のようになります。
foobar=$'foo\0bar' # foobar='foo' + null byte + 'bar'
echo "${#foobar}" # print length of $foobar
実際には文字列の末尾の後に表示されます:ので、3
実際に印刷されます。$foobar
'foo'
bar
繰り返しますが、その部分は不明なのでecho $'foo\0bar'
印刷してください。foo
echo
\0bar
ご覧のとおり、このシーケンスは\0
実際には -style 文字列で非常に誤解を招くことがあります。$'...'
文字列ではヌルバイトのように見えますが、最終的にそのようには機能しません。最初の例では、あなたのread
コマンドはです-d $'\0'
。これはうまくいきますが、うまく-d ''
いくからです! (これは明示的に文書化された機能ではありませんが、read
同じ方法で動作すると仮定します。''
文字列が空であるため、終了nullバイトがすぐに表示されます。「最初の文字」を使用することで文書化されています。-d delim
Delim"、"最初の文字"が文字列の終わりを超えている場合でも動作します!)
しかし、あなたの例からfind
わかるように、はい1つのコマンドはNULLバイトを印刷でき、そのバイトはそれを入力として読み取る別のコマンドにパイプできます。どの部分もヌルバイトの格納に依存しません。Bashの文字列から。 2番目の例の唯一の問題は、$'\0'
コマンドの引数にそれを使用できないことです。echo "$file"$'\0'
ユーザーが望む場合は、最後にヌルバイトが印刷されます。
echo
printf
したがって、-style文字列と同じタイプのエスケープシーケンスをサポートする代わりに使用できます。$'...'
これにより、文字列にnullバイトを含めずにnullバイトを印刷できます。次のようになります。
for file in * ; do printf '%s\0' "$file" ; done \
| while IFS= read -r -d '' ; do echo "$REPLY" ; done
または単に次のようになります:
printf '%s\0' * \
| while IFS= read -r -d '' ; do echo "$REPLY" ; done
(注:実際にはNULLバイトを処理して印刷するフラグがecho
ありますが、ファイル名の特殊シーケンスも処理しようとします。したがって、この方法はより強力です。)-e
\0
printf
ところで、殻が少しあります。する文字列にはヌルバイトが許可されます。たとえば、あなたの例はZshでうまく動作します(デフォルト設定の前提)。ただし、シェルが何であれ、Unixファミリーのオペレーティングシステムはプログラム引数にヌルバイトを含める方法を提供していないため(プログラム引数はCスタイルの文字列として渡されるため)、常にいくつかの制限があります。 (あなたの例はecho
組み込みシェルなので、Zshでのみ機能するので、Zshは他のプログラム呼び出しのためのOSサポートに依存せずにそれを呼び出すことができます。代わりに、組み込みシェルをバイパスして次のcommand echo
ことを見るecho
ことができます。echo
型プログラムを使用する$PATH
Bashと同様に、Zshでも同じ動作が発生します。)