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'
単にprintします。foo
echo
\0bar
ご覧のように、\0
シーケンスは実際には$'...'
-style文字列では非常に誤解を招きます。文字列内ではヌルバイトのように見えますが、そのようには機能しません。最初の例では、read
コマンドにはがあり-d $'\0'
ます。これは機能しますが、それ-d ''
も機能するからです!(これはの明示的に文書化された機能ではありませんread
が、同じ理由で機能すると仮定します:''
空の文字列であるため、その終端のヌルバイトがすぐに来ます。「デリムの最初の文字」を使用して文書化され、 「最初の文字」が文字列の終わりを超えている場合!)-d delim
あなたから知っているとしてではなくfind
例として、それはあるヌルバイトをプリントアウトするためのコマンドについて、および入力として、それを読み込み、別のコマンドにパイプされるそのバイトに対して可能。Bash内の文字列に nullバイトを格納することに依存する部分はありません。2番目の例の唯一の問題は$'\0'
、コマンドの引数で使用できないことです。echo "$file"$'\0'
あなたがそれを望んでいることがわかっている場合に限り、最後にnullバイトを喜んで印刷することができます。
したがって、を使用する代わりに、を使用してecho
、-style文字列printf
と同じ種類のエスケープシーケンスをサポートでき$'...'
ます。そうすれば、文字列内にヌルバイトを入れなくても、ヌルバイトを印刷できます。次のようになります。
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
(注:echo
実際には、nullバイトを-e
処理\0
して印刷できるフラグもありますが、ファイル名に含まれる特別なシーケンスを処理しようとするため、このprintf
アプローチはより堅牢です。)
尚、一部のシェルがあります nullは内部の文字列をバイト許します。たとえば、Zshでの例は正常に機能します(デフォルト設定を前提としています)。ただし、シェルに関係なく、Unixライクなオペレーティングシステムは、プログラムへの引数にヌルバイトを含める方法を提供しません(プログラムの引数はCスタイルの文字列として渡されるため)。常にいくつかの制限があります。(あなたの例では、という理由だけでZshの中で作業することができますecho
Zshのは、他のプログラムを呼び出すためのOSのサポートに頼ることなく、それを呼び出すことができますので。あなたが使用している場合、シェル組み込みであるcommand echo
代わりにしecho
、それは組み込みをバイパスし、スタンドアロンで使用ようecho
にプログラムを$PATH
、 ZshでBashと同じ動作が見られます。)
-d ''
すでに区切りを意味する場合、IFSが何も設定されないのはなぜ\0
ですか?ここで説明を見つけました:stackoverflow.com/questions/8677546/…–