「コマンドの置き換え:入力でヌルバイトを無視する」を無視する方法は?

「コマンドの置き換え:入力でヌルバイトを無視する」を無視する方法は?

次のLinuxシェルコマンドがあります。

echo $(python3 -c 'print("Test"+"\0"+"M"*18)') | nc -u [IP] [PORT]

私の意図は、ステートメントの出力をprintnetcatコマンドにパイプすることです。 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; })を使用して最初に\0printfを使用して「Test」バイトとNULバイト()を印刷し、次にprintfを使用して幅0の文字列(%.0s)を印刷してからM18回を印刷します。グループ全体コマンドの出力はにパイプされますnc

printfこれは、フォーマットが「すべての引数を消費するために必要に応じて再利用」(参考文献を参照help printf)され、中括弧拡張が1から18の整数に拡張され、ゼロが1つだけのprintf形式の文字列を提供するために機能します{1..18}。パラメータは18です(幅文字列フィールドと文字通りの「M」文字です。したがって、18M文字が出力されます。

代わりに、hexdumper(orなど)にパイプして、グループコマンドが出力するxxd内容を正確に確認できます。hdnc

$ { 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

printPythonは自動的に改行(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

おすすめ記事