私は現在netcatに入力としてパイプされるバイトを生成するスクリプトを作成しようとしています。
スクリプトのアイデアは次のとおりです。
(perl -e "print \"$BYTES\x00\";
cat file;
perl -e "print \"More bytes\"x16 . \"\r\n\"";) | netcat ip port
コマンドを実行するためにサブシェルとコマンドの置き換え(例:$())を試しました。ところで、コマンド置換を使用すると、スクリプトの出力が誤った理由を理解できません。複数のコマンドを実行すると、コマンド置換が出力を誤ってパイプするようです。なぜこれが起こるのか説明できますか?
編集する
以下は、コマンド置換を使用したバリエーションです。
$(perl -e "print \"$BYTES\x00\";
cat file;
perl -e "print \"More bytes\"x16 . \"\r\n\"";) | netcat ip port
答え1
さて、分析してみましょう。サブシェルはチェーンでアイテムを実行します(つまり、グループ化)。コマンドチェーンを()
。ただし、サブシェルの内容が実行時に一緒に結合されることを除いて、サブシェルは単一のコマンドであるかのように引き続き使用できます。つまり、サブシェルはまだ存在するため、stdin
サブシェルの内外にパイプを接続できますstdout
。stderr
一方、コマンドの置換は、単にコマンドを一緒に接続するのとは異なります。対照的に、コマンド置換は変数アクセスと少し似ていますが、関数呼び出しを使用します。コマンドとは異なり、変数には標準のファイル記述子がないため、通常は変数の内外に何もパイプできず、コマンドの置き換えも同様です。
これをより明確にするために、以下には不明瞭であるかもしれませんが、正確な一連の例と理解しやすくなると思われる一連の例があります。
date -u
コマンドが以下を提供すると仮定します。
Thu Jul 2 13:42:27 UTC 2015
しかし、私たちはこのコマンドの出力を操作しようとしています。それでは、次のようにパイプしてみましょうsed
。
user@host~> date -u | sed -e 's/ / /g'
Thu Jul 2 13:42:27 UTC 2015
うわー、本当に面白いですね!以下は上記とまったく同じです(シェルのマニュアルページで読むことができるいくつかの環境上の違いを除いて)。
user@host~> (date -u) | sed -e 's/ / /g'
Thu Jul 2 13:42:27 UTC 2015
私たちがすることはグループだけなので、これは驚くべきことではありませんdate -u
。しかし、次のようにすると、最初は少し奇妙に見える結果が表示されます。
user@host~> $(date -u) | sed -e 's/ / /g'
command not found: Thu
これは、出力を$(date -u)
正確に入力するのと同じです。date -u
したがって、上記は次のようになります。
user@host~> Thu Jul 2 13:42:27 UTC 2015 | sed -e 's/ / /g'
もちろん、Thu
これはコマンドではないため、エラーが発生します(少なくとも私が知っているわけではありません)。確かに何もパイプしませんstdout
(だからsed
何の入力も得られません)。
ただし、コマンド置換が変数のように機能することを知っているので、変数の値を別のコマンドにパイプする方法を知っているので、この問題を簡単に解決できます。
user@host~> echo $(date -u) | sed -e 's/ / /g'
Thu Jul 2 13:42:27 UTC 2015
しかし、Bashの他の変数と同様に、quoteコマンドで置き換える必要があります""
。
今より簡単な例として、次のことを考えてみましょう。
user@host~> pwd
/home/hypothetical
user@host~> echo pwd
pwd
user@host~> echo "$(pwd)"
/home/hypothetical
user@host~> echo "$HOME"
/home/hypothetical
user@host~> echo (pwd)
error: your shell will tell you something weird that roughly means “Whoa! you tried to have me echo something that isn't text!”
user@host~> (pwd)
/home/hypothetical
これより簡単に説明できる方法はありません。コマンド置換は、サブシェルがまだコマンドのように実行される変数アクセスのように機能します。
答え2
サブシェル
(command)
command
サブシェルで実行されます。これは複数のコマンドがある場合に便利です。
(ls) | wc
出力ls
をにパイプするので、はっきりと書くことがwc
できますls | wc
。(ls ; date) | wc
ls
date
合計の出力をwc
。を使用するとのみ配管にls ; date | wc
なります。date
wc
置換
$(command)
実行され、command
出力に置き換えられます。例えば
echo $(date)
$(date)
に置き換えられ、Thu Jul 2 15:20:43 CEST 2015
結果は次のようになります。
echo Thu Jul 2 15:20:43 CEST 2015
二つを合わせる
2つを組み合わせることができます。
file=/hello/word
( printf "%s has %d bytes\n" "${file}" $(wc -c < "$file") ; date ) | netcat ...
"$file"
ここでは、またはを使用できます"${file}"
。
ファイル名を引用することを忘れないでください。ファンタジーの世界ではファイル名が一般的なファイルですが、現実の世界ではファイル名に改行、スペース、カンマ、タブ、括弧が含まれることがよくあります。