サブシェル

サブシェル

私は現在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サブシェルの内外にパイプを接続できますstdoutstderr

一方、コマンドの置換は、単にコマンドを一緒に接続するのとは異なります。対照的に、コマンド置換は変数アクセスと少し似ていますが、関数呼び出しを使用します。コマンドとは異なり、変数には標準のファイル記述子がないため、通常は変数の内外に何もパイプできず、コマンドの置き換えも同様です。

これをより明確にするために、以下には不明瞭であるかもしれませんが、正確な一連の例と理解しやすくなると思われる一連の例があります。

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) | wclsdate合計の出力をwc。を使用するとのみ配管にls ; date | wcなります。datewc

置換

$(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}"

ファイル名を引用することを忘れないでください。ファンタジーの世界ではファイル名が一般的なファイルですが、現実の世界ではファイル名に改行、スペース、カンマ、タブ、括弧が含まれることがよくあります。

関連情報