BashでNULLバイトを使用する方法は?

BashでNULLバイトを使用する方法は?

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'印刷してください。fooecho\0bar

ご覧のとおり、このシーケンスは\0実際には -style 文字列で非常に誤解を招くことがあります。$'...'文字列ではヌルバイトのように見えますが、最終的にそのようには機能しません。最初の例では、あなたのreadコマンドはです-d $'\0'。これはうまくいきますが、うまく-d ''いくからです! (これは明示的に文書化された機能ではありませんが、read同じ方法で動作すると仮定します。''文字列が空であるため、終了nullバイトがすぐに表示されます。「最初の文字」を使用することで文書化されています。-d delimDelim"、"最初の文字"が文字列の終わりを超えている場合でも動作します!)

しかし、あなたの例からfindわかるように、はい1つのコマンドはNULLバイトを印刷でき、そのバイトはそれを入力として読み取る別のコマンドにパイプできます。どの部分もヌルバイトの格納に依存しません。Bashの文字列から。 2番目の例の唯一の問題は、$'\0'コマンドの引数にそれを使用できないことです。echo "$file"$'\0'ユーザーが望む場合は、最後にヌルバイトが印刷されます。

echoprintfしたがって、-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\0printf


ところで、殻が少しあります。する文字列にはヌルバイトが許可されます。たとえば、あなたの例はZshでうまく動作します(デフォルト設定の前提)。ただし、シェルが何であれ、Unixファミリーのオペレーティングシステムはプログラム引数にヌルバイトを含める方法を提供していないため(プログラム引数はCスタイルの文字列として渡されるため)、常にいくつかの制限があります。 (あなたの例はecho組み込みシェルなので、Zshでのみ機能するので、Zshは他のプログラム呼び出しのためのOSサポートに依存せずにそれを呼び出すことができます。代わりに、組み込みシェルをバイパスして次のcommand echoことを見るechoことができます。echo型プログラムを使用する$PATHBashと同様に、Zshでも同じ動作が発生します。)

関連情報