2017-03-22 24 views
3

私は最近、デバッグされたプログラムのstdinを供給するためにgdb<<<のトリックがストリームからヌルバイトをフィルタリングしていることを発見しました。ここでなぜ '<<<'フィルタリングはgdbのnullバイトで、 '<()'はしませんか?

は、それがnullバイトをフィルタリングすることを証言する(誰でも自宅で再現することができるはず)小さな例です:

bashの固有 <() process substitutionを使用すると、NULLバイトを残して、
$> python -c 'print("A\x00" * 10)' | cat -A 
A^@A^@A^@A^@A^@A^@A^@A^@A^@A^@$ 
$> gdb /bin/cat 

... gdb license prelude ... snip... 

(gdb) r -A <<< $(python -c 'print("A\x00" * 10)') 
Starting program: /bin/cat -A <<< $(python -c 'print("A\x00" * 10)') 
/bin/bash: warning: command substitution: ignored null byte in input 
AAAAAAAAAA$ 
[Inferior 1 (process 3798) exited normally] 

gdb内のプログラムstdinに達する:だから

(gdb) r -A < <(python -c 'print("A\x00" * 10)') 
Starting program: /bin/cat -A < <(python -c 'print("A\x00" * 10)') 
A^@A^@A^@A^@A^@A^@A^@A^@A^@A^@$ 
[Inferior 1 (process 3804) exited normally] 

、私はいつも<<<<()が同じトン程度やっていたことを考えていますヒンジは明らかに間違っています。私は2つの方法の間の違いが何であるかを知っているし、その旨をbash神秘的なエラーメッセージについての説明がしたい:

/bin/bash: warning: command substitution: ignored null byte in input 

すべてのヘルプは歓迎以上です!

+1

開始するために '' <<<文字列の末尾に改行文字を追加します。 – Inian

答えて

2

だから、私は常にその<<<<()は今、明らかに間違っている同じことをやっていたのに。

これらはしません。全く同じと同じものです。 <<<オペレータは、関連するプロセスの標準入力に "here string"をリダイレクトします。 <()を介したプロセス置換は、指定されたコマンドの標準出力を読み取ることができるファイル(通常はFIFOなど)の名前をに展開します。あなたが意味するように見える何

は($()またはバッククォートを経由して)コマンド置換と<<<の組み合わせは、プロセス置換を有する<を経由して通常の標準入力のリダイレクトの組み合わせと同じ事をしていることです。 このは真ですが、あなたが発見したように、セマンティクスは全く同じではありません。

私は重要な違いがここに文字列からリダイレクトすると、最初の文字列を生成する必要があることである2つの方法の間の違いが何であるかを知りたいとbashの神秘的なエラーメッセージ

についての説明を持っているでしょうプロセス置換をリダイレクトすると、関連付けられたプロセスによってが直接に読み込まれます。

最終的に、受信した診断は、予期しない動作がコマンド置換の動作によって発生したことを意味し、動作は<<<ではありません。私はそれが明示的に文書化されていませんが、コマンド置換を処理するときにBashがプログラム出力からヌル文字を取り除いても驚くことはありません。 C文字列はヌル文字で終わるため、ヌル文字を含む文字シーケンスを表すことはできません。

アップデート:また

なお、他の回答にコメントで観察@sorontarは、POSIXがコマンド置換でコマンドの出力がnullバイトが含まれている場合、結果は不定であることを言うように。したがって、Bashは空のバイトを取り除くことができます。あるいは、POSIXの適合性を犠牲にすることなく、実際にはそれが見えるほど多かれ少なかれ必要なことを行うことができます。この点に関して、他のシェルはBashとは異なる選択をするかもしれません。これは、コマンドの出力に現れるヌルバイトが予見可能な可能性があるコマンド置換を避ける優れた理由です。

この<<<はここに文字列であり、変数の展開ルールの対象となる(場合によっては同様の理由で使用することができますが)

+0

ああ、私はまったく間違っていました!あなたの説明に感謝します!今は本当にクリスタルクリアです! – perror

3

既に述べたように、これらの2つの方法は、同じものではありません。 Bashでは、変数値にnullバイトが存在しません。

一方、プロセス置換<()はファイルとして扱われ、ファイルにはヌル文字が使用できます。

あなたが気づいた違いは、このbashの動作によるものです。 異なるシェルでこの制限が有効でない可能性があります。

より多くのテスト:

$ echo -en "A\x00A\x00A" |od -t x1c 
0000000 41 00 41 00 41 
      A \0 A \0 A 
0000005 

$ a=$(echo -en "A\x00A\x00A");echo "$a" |od -t x1c 
bash: warning: command substitution: ignored null byte in input 
0000000 41 41 41 0a 
      A A A \n 
0000004 


$ cat <(echo -en "A\x00A\x00A") |od -t x1c #this is treated as file 
0000000 41 00 41 00 41 
      A \0 A \0 A 
0000005 
$ cat <<<$(echo -en "A\x00A\x00A") |od -t x1c #this is considered a variable 
bash: warning: command substitution: ignored null byte in input 
0000000 41 41 41 0a 
      A A A \n 
0000004 
+2

異なるシェルの振る舞いに関しては、 '<<<'演算子はPOSIXシェルの標準的な機能ではなく、Bash拡張であることに注意することが重要です。一方、別のシェルがヌル文字を含む文字列を実際に収容できることは、まったくもっともらしいです。 –

+2

@JohnBollinger 'zsh -c 'cat <<< $(echo -en" A \ x00A \ x00A ")| od -t x1c"を試してください。実際には、zshは '\ 0'バイトを許可します。 – sorontar

+0

さらに@JohnBollinger [出力にnullバイトが含まれている場合、動作は不明です。](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_03)。 「コマンド置換」に**明示的な「特別免除」**があります。 – sorontar

関連する問題