次のことを理解する方法を考えていました:
コマンドのstdoutを別のコマンドのstdinにパイプすることは、強力な手法です。しかし、複数のコマンドの標準出力をパイプする必要がある場合はどうなりますか?これがプロセス置換の出番です。
つまり、プロセス置換はパイプでできることは何でもできますか?
プロセス置換はできますが、パイプはできませんか?
回答
それらの違いは、コマンドラインで少し実験することです。 <
文字の使用は視覚的に類似していますが、リダイレクトやパイプとは非常に異なる動作をします。
コマンド。
$ date | cat Thu Jul 21 12:39:18 EEST 2011
これは無意味な例ですが、cat
は、STDINでdate
の出力を受け入れ、それを吐き出しました。同じ結果は、プロセス置換によっても達成できます:
$ cat <(date) Thu Jul 21 12:40:53 EEST 2011
ただし、舞台裏で起こったことは異なります。STDINストリームが与えられる代わりに、cat
には実際に開く必要のあるファイルの名前が渡されました。この手順は、cat
の代わりにecho
を使用して確認できます。
$ echo <(date) /proc/self/fd/11
catがファイル名を受け取ると、ファイルのコンテンツを読み取ります。一方、echoは、渡されたファイルの名前を表示しただけです。この違いは、置換を追加するとより明白になります。
$ cat <(date) <(date) <(date) Thu Jul 21 12:44:45 EEST 2011 Thu Jul 21 12:44:45 EEST 2011 Thu Jul 21 12:44:45 EEST 2011 $ echo <(date) <(date) <(date) /proc/self/fd/11 /proc/self/fd/12 /proc/self/fd/13
Itプロセス置換(ファイルを生成する)と入力リダイレクト(ファイルをSTDINに接続する)を組み合わせることができます。
$ cat < <(date) Thu Jul 21 12:46:22 EEST 2011
見た目はほとんど同じですが、今回、catにはファイル名ではなくSTDINストリームが渡されました。これは、echoで試すことで確認できます。
$ echo < <(date) <blank>
echoはSTDINを読み取らないため、引数は渡されず、何も取得されません。
パイプと入力リダイレクトにより、コンテンツがSTDINストリームに押し出されます。プロセス置換はコマンドを実行し、その出力を特別な一時ファイルに保存してから、コマンドの代わりにそのファイル名を渡します。使用しているコマンドが何であれ、それはファイル名として扱われます。作成されるファイルは通常のファイルではなく、名前付きパイプであり、不要になると自動的に削除されることに注意してください。
コメント
回答
他の方法では不可能なプロセス置換でできる3つのことがあります。
複数のプロセス入力
diff <(cd /foo/bar/; ls) <(cd /foo/baz; ls)
ありますパイプでこれを行う方法はありません。
STDINの保持
次のように設定します:
curl -o - http://example.com/script.sh #/bin/bash read LINE echo "You said ${LINE}!"
そしてあなたはそれを直接実行したいと思っています。以下は惨めに失敗します。 BashはすでにSTDINを使用してスクリプトを読み取っているため、他の入力は不可能です。
curl -o - http://example.com/script.sh | bash
ただし、この方法は完全に機能します。
bash <(curl -o - http://example.com/script.sh)
アウトバウンドプロセス置換
また、プロセス置換は逆の方法でも機能することに注意してください。したがって、次のようなことができます。
(ls /proc/*/exe >/dev/null) 2> >(sed -n \ "/Permission denied/ s/.*\(\/proc.*\):.*/\1/p" > denied.txt )
これは少し複雑な例ですが、 stdout を
、 stderr をsedスクリプトにパイプして、”アクセスが拒否されたファイルの名前を抽出します”エラーが表示された後、これらの結果をファイルに送信します。
最初のコマンドと stdout リダイレクトは括弧内にあることに注意してください。 ( subshell )そのコマンドの結果のみが/dev/null
に送信され、行の残りの部分を混乱させないようにします。
コメント
- ‘は
diff
で注目に値しますたとえば、cd
が失敗する可能性がある場合に注意する必要があります:diff <(cd /foo/bar/ && ls) <(cd /foo/baz && ls)
。 - “標準ストリームの配管中”:isn ‘これは配管ではなく、FIFOファイルを通過していることを指摘しますか?
- @Gauthier no;コマンドは、FIFOではなく、ファイル記述子への参照に置き換えられます。したがって、” echo <(echo)”は / dev / fd / 63 “は、FD番号63から読み取りまたは書き込みを行う特殊な文字デバイスです。
回答
bash
またはその他の高度なシェルについて話していると思います。シェルにはプロセス置換がありません。
bash
手動ページレポート:
プロセス置換
プロセス置換は、名前付きパイプ(FIFO)または開いているファイルに名前を付ける/ dev / fdメソッドをサポートするシステムでサポートされています。 <(リスト)または>(リスト)の形式を取ります。プロセスリストは、入力または出力をFIFOまたは/ dev / fd内のファイルに接続して実行されます。このファイルの名前は、展開の結果として現在のコマンドに引数として渡されます。 >(list)形式が使用されている場合、ファイルに書き込むとリストへの入力が提供されます。 <(list)形式を使用する場合は、引数として渡されたファイルを読み取ってリストの出力を取得する必要があります。使用可能な場合は、プロセス置換パラメータと変数の展開、コマンド置換、算術展開と同時に実行されます。
つまり、実用的な観点から、次のように使用できます。次のような式
<(commands)
パラメータとしてファイルを必要とする他のコマンドのファイル名として。または、そのようなファイルにリダイレクトを使用することもできます。
while read line; do something; done < <(commands)
質問に戻ると、プロセス置換とパイプにはあまり共通点がないようです。
複数のコマンドの出力を順番にパイプする場合は、次のいずれかの形式を使用できます。
(command1; command2) | command3 { command1; command2; } | command3
プロセス置換でリダイレクトを使用することもできます
command3 < <(command1; command2)
最後に、command3
がファイルパラメータを受け入れる場合(stdinの代わりに) )
command3 <(command1; command2)
コメント
- so <( )と< <()は同じ効果をもたらしますよね?
- @solfish:exaclltyではありません:firse canファイル名が予期される場所で使用され、2番目はそのファイル名の入力リダイレクトです
回答
コマンドはファイルのリストを引数として受け取り、それらのファイルを入力として処理します(または出力ですが、一般的ではありません)、これらの各ファイルは、プロセス置換によって透過的に提供される名前付きパイプまたは/ dev / fd疑似ファイルにすることができます:
$ sort -m <(command1) <(command2) <(command3)
これsortはコマンドライン上の入力ファイルのリストを取得できるため、ソートする3つのコマンドの出力を「パイプ」します。
コメント
- IIRC <(コマンド)構文はbashのみの機能です。
- @Philomath:’ ZSHも。
- そうですね、ZSHにはすべてがあります…(または少なくともそうしようとします)。
- @Philomath:プロセス置換は他のシェルでどのように実装されていますか?
- @Philomath
<()
は、多くの高度なシェル機能と同様に、元々はksh機能であり、bashとzshで採用されました。psub
は特に魚の機能であり、POSIXとは関係ありません。
回答
プロセス置換は、command
の出力をとして使用する<(command)
の形式に限定されないことに注意してください。ファイル。 command
への入力としてファイルをフィードする>(command)
の形式にすることもできます。これは、@ enzotibの回答のbashマニュアルの引用にも記載されています。
上記のdate | cat
の例では、のプロセス置換を使用するコマンド同じ効果を達成するには、>(command)
を作成します。
date > >(cat)
>
>(cat)
の前が必要です。これも、@ Calebの回答のようにecho
で明確に説明できます。
$ echo >(cat) /dev/fd/63
したがって、余分な>
がなければ、date >(cat)
はstderrにメッセージを出力するdate /dev/fd/63
と同じです。
ファイル名のみをパラメーターとして受け取り、またはstdout
。これを説明するために、過度に単純化されたスクリプトpsub.sh
を使用します。 psub.sh
の内容は
#!/bin/bash [ -e "$1" -a -e "$2" ] && awk "{print $1}" "$1" > "$2"
基本的に、両方の引数がファイルであることをテストします(必ずしも通常ではありません)。ファイル)、この場合は、awkを使用して"$1"
の各行の最初のフィールドを"$2"
に書き込みます。次に、これまでに述べたすべてを組み合わせたコマンドは、
./psub.sh <(printf "a a\nc c\nb b") >(sort)
これは出力されます
a b c
これは
printf "a a\nc c\nb b" | awk "{print $1}" | sort
と同等ですが、以下は機能しないため、ここではプロセス置換を使用する必要があります
printf "a a\nc c\nb b" | ./psub.sh | sort
または同等の形式
printf "a a\nc c\nb b" | ./psub.sh /dev/stdin /dev/stdout | sort
./psub.sh
もstdin
上記以外に、そのような同等の形式は存在せず、その場合、プロセス置換の代わりに使用できるものはありません(もちろん、名前付きパイプまたは一時ファイルですが、それは別の話です。
[[ -p <(date) ]] && echo true
。これにより、bash4.4または3.2で実行するとtrue
が生成されます。