次のLinuxシェルコマンドがあります。
echo $(python3 -c 'print("Test"+"\0"+"M"*18)') | nc -u [IP] [PORT]
私の意図は、ステートメントの出力をprint
netcatコマンドにパイプすることです。 netcat コマンドは、デフォルトで着信文字列の標準出力を返す一部のサービスのソケットを作成します。
ここで問題は、このコマンドを実行しようとすると、次のメッセージが表示されることです。
-bash: warning: command substitution: ignored null byte in input
;私のnullバイトは\0
無視されます。しかし、私はnullバイトが無視されることを望まない。
nullバイトを無視せずに、私が指定したように正確に入力を受け取るようにシステムに指示するにはどうすればよいですか?
Google検索を数回試しましたが、正直なところあまり役に立ちませんでした。また、素晴らしい記事へのリンクを提供していただきありがとうございます。
編集する
使用に有効ですprintf
。
通常、合格python3 -c 'print("Test"+"\0"+"M"*18)'
も有効です。貴重な@casの説明。私はprintf
これがより速いので、おそらくこれに固執すると思います(もちろん私の場合、速度は特に重要ではありませんが)。
すべての貢献者に感謝します:-)。
答え1
Bashの文字列できないNUL バイトを含み、コマンド置換のすべての出力を含みます。 Bash 変数には NUL も含めることはできません。これは無視または上書きすることはできません(一部のコマンドでは改行表示と同様にNUL表示printf
として使用して問題を解決できますが)。\0
\n
nc
@CharlieWilsonの答えと同じように、コマンドを置き換えることなくPythonの出力をPythonに直接パイプすることができますが、echo
それは必要ありません。 Bashには、printf
目的のタスクを実行する機能が組み込まれています。例えば
{ printf 'Test\0'; printf -- '%.0sM' {1..18}; } | nc -u [IP] [PORT]
これは、グループコマンド({ list; }
)を使用して最初に\0
printfを使用して「Test」バイトとNULバイト()を印刷し、次にprintfを使用して幅0の文字列(%.0s
)を印刷してからM
18回を印刷します。グループ全体コマンドの出力はにパイプされますnc
。
printf
これは、フォーマットが「すべての引数を消費するために必要に応じて再利用」(参考文献を参照help printf
)され、中括弧拡張が1から18の整数に拡張され、ゼロが1つだけのprintf形式の文字列を提供するために機能します{1..18}
。パラメータは18です(幅文字列フィールドと文字通りの「M」文字です。したがって、18M文字が出力されます。
代わりに、hexdumper(orなど)にパイプして、グループコマンドが出力するxxd
内容を正確に確認できます。hd
nc
$ { printf 'Test\0'; printf -- '%.0sM' {1..18}; } | hd
00000000 54 65 73 74 00 4d 4d 4d 4d 4d 4d 4d 4d 4d 4d 4d |Test.MMMMMMMMMMM|
00000010 4d 4d 4d 4d 4d 4d 4d |MMMMMMM|
00000017
これにより、5番目の文字がNUL()であることがわかります00
。
print
Pythonは自動的に改行(0a
)を追加するため、Pythonの出力はわずかに異なります。
$ python3 -c 'print("Test"+"\0"+"M"*18)' | hd
00000000 54 65 73 74 00 4d 4d 4d 4d 4d 4d 4d 4d 4d 4d 4d |Test.MMMMMMMMMMM|
00000010 4d 4d 4d 4d 4d 4d 4d 0a |MMMMMMM.|
00000018
転送したいプログラムにnc
改行文字が必要な場合は、print itを使用できますprintf '\n'
。またはecho
。
$ { printf 'Test\0'; printf -- '%.0sM' {1..18}; echo; } | hd
00000000 54 65 73 74 00 4d 4d 4d 4d 4d 4d 4d 4d 4d 4d 4d |Test.MMMMMMMMMMM|
00000010 4d 4d 4d 4d 4d 4d 4d 0a |MMMMMMM.|
00000018
注:グループコマンドの詳細については、以下を参照してman bash
検索してくださいCompound Commands
。
{ list; }
list
現在のシェル環境で実行できます。list
〜しなければならない改行またはセミコロンで終了します。これをグループコマンドと呼びます。戻り状態はリストの終了状態です。
(
メタ文字とは異なり、およびは予約語)
であるため、認識された予約語が許可されている場所に表示する必要があります。ハイフンを使用しないため、スペースやその他のシェルメタ文字で区切る必要があります。{
}
list
しかし、printfを使用することはPythonを実行し、小さなPythonスクリプトをコンパイルするオーバーヘッドを避けるため、Pythonを使用するよりも高速です。これは現代のシステムのワンタイムコマンドとは関係ありませんが、ループで実行される場合は関係ありません。たとえば、約10年前の6コアAMD Phenom II 1090Tでは、次のようになります。
$ time { printf 'Test\0'; printf -- '%.0sM' {1..18}; }
TestMMMMMMMMMMMMMMMMMM
real 0m0.000s user 0m0.000s sys 0m0.000s
$ time python3 -c 'print("Test"+"\0"+"M"*18)'
TestMMMMMMMMMMMMMMMMMM
real 0m0.036s user 0m0.028s sys 0m0.008s
printfは実際には0秒かかり時間がかかりませんが、$TIMEFORMAT文字列で表現するには時間が短すぎます。
Perlは小さなスクリプトを起動、コンパイル、実行するのにPythonよりも少し高速ですが、まだシェルループで繰り返し実行したくありません。
$ time perl -e 'print "Test\0" . "M" x 18 . "\n"'
TestMMMMMMMMMMMMMMMMMM
real 0m0.008s user 0m0.000s sys 0m0.009s
または、はるかに高速なPerlのprintfを使用してください。
$ time perl -e 'printf "Test\0%s\n", "M" x 18'
TestMMMMMMMMMMMMMMMMMM
real 0m0.003s user 0m0.003s sys 0m0.000s
答え2
echo
私はそれが問題で不要だと思います。
この行を考慮してください。
python3 -c 'print("Test"+"\0"+"M"*18)' | nc -u [IP] [PORT]