$ echo 123 | cat
123
私が期待どおりに実行しています。両方のコマンドが同じシェルで実行されています。
>( ... )
ただし、シェルの1つのコマンド出力をサブシェルの2番目のコマンドに関連付ける式を使用してそれを連結すると、次の結果が得られます。
$ echo 123 >(cat)
123 /dev/fd/63
他の値にも同様に適用されます。
$ echo 101 >(cat)
101 /dev/fd/63
$ echo $BASHPID >(cat)
3252 /dev/fd/63
command1 >(command2)
と同じだと思いますcommand1 | command2
が、command1 >(command2)
各コマンドは異なるシェル内にあるので、同じ出力を持つ必要があります。私はどこで間違っていますか?
答え1
プロセス置換は>(thing)
ファイル名で置き換えられます。ファイル名は、thing
内部的に置き換えられる標準入力に接続されたファイルに対応します。
以下は、その使用のより良い例です。
$ sort -o >(cat -n >/tmp/out) ~/.profile
その後、ファイルがソートされ、~/.profile
出力がcat -n
その出力に送信され、行が列挙され、結果が/tmp/out
。
したがって、あなたの質問に答えると、echo
2つのパラメータ123
の合計が得られたため、この出力が得られます/dev/fd/63
。プロセス置換では、/dev/fd/63
プロセスの標準入力に関連付けられたファイルです。cat
サンプルコードを少し修正してください。
$ echo 101 > >(cat)
これは101
標準出力としてのみ生成されます(の出力はecho
入力として使用されるファイルにリダイレクトされ、cat
そのcat
ファイルの内容は標準出力として生成されます)。
また、cmd1 | cmd2
パイプラインではcmd2
同じシェルでまったく実行されない可能性がありますcmd1
(使用しているシェルの実装によって異なります)。 ksh93
説明どおりに動作します(同じシェル)。bash
サブシェルの作成中cmd2
(lastpipe
シェルオプションが設定され、ジョブ制御が有効になっていない場合)
答え2
完全性のために
cmd1 >(cmd2)
ほとんどは同じです
cmd1 | cmd2
シェルではyash
、シェルでのみ可能です。
その殻の中には>(cmd)
プロセスがありますリダイレクト>(cmd)
//とは対照的にksh
、bash
これはzsh
プロセスです。置換。
cmd1 >(cmd2)
にはyash
wait がないので厳密に等しくないので、次のようなものを見つけるcmd2
ことができます。
$ yash -c 'echo A >(cat); echo B'
B
A
$ yash -c 'echo A | cat; echo B'
A
B
これと比較して、置換書き込みを開くときに出力を/dev/fd/<x>
。<x>
cmd
このシェルにはプロセス置換がksh
導入されていますが、それをリダイレクトの引数として渡すことはできません。
ksh -c 'cmd1 > >(cmd2)'
プロセスリダイレクトシミュレーションがyash
機能しません。そこで、次のように代替結果として生成されたファイル名をコマンドの引数として渡す必要があります。
ksh -c 'diff <(echo a) <(echo b)'
それはbash
内外で動作しますzsh
。
ただし、bash
forのプロセスリダイレクトと同様に、yash
シェルはコマンド()を待ちませんcmd2
。だから:
$ bash -c 'echo A > >(cat); echo B'
B
A
ksh
プロセスの交換は、yash
次の方法でシミュレートできます。
cmd1 /dev/fd/5 5>(cmd2)
良い:
diff /dev/fd/3 3<(echo a) /dev/fd/4 4<(echo b)
答え3
なぜならこれがプロセス交換が行うことです。, 置換項目内のコマンドがファイル名で表示されます。内部的には、パイプを介してコマンドを接続して基本コマンドへ/dev/fd/NN
のパスを提供するため、パイプですでに開いているファイル記述子を開くことができます。
パイプとは異なります。パイプ接続には、ファイル名のように見えるものは含まれstdout
ません。stdin
プロセスの置き換えは、1つのコマンドラインで複数の置換を実行できるという点でより柔軟ですが、名前でファイルを開くにはデフォルトのコマンドが必要です(代わりにcat
)echo
。
次の手順を実行して、プロセス置換を含むパイプラインをシミュレートできます。
echo foo > >(cat -n)
答え4
$ echo 1 >(cat > /dev/null)
1 /dev/fd/63
$ echo echo >(cat /dev/null)
echo /dev/fd/63
# We can trace how the commands are executed
# so long as we avoid using shell builtin commands,
# and run the equivalent external program instead, i.e. /usr/bin/echo
$ strace -f -e execve bash -c '/usr/bin/echo >(cat /dev/null)'
execve("/usr/bin/bash", ["bash", "-c", "/usr/bin/echo >(cat /dev/null)"], [/* 56 vars */]) = 0
strace: Process 4213 attached
[pid 4212] execve("/usr/bin/echo", ["/usr/bin/echo", "/dev/fd/63"], [/* 56 vars */]) = 0
strace: Process 4214 attached
[pid 4214] execve("/usr/bin/cat", ["cat", "/dev/null"], [/* 56 vars */]/dev/fd/63
) = 0
[pid 4212] +++ exited with 0 +++
[pid 4214] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=4214, si_uid=1001, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++
# Apparently, the order of evaluation is arranged so this works nicely:
$ echo 1 > >(cat > /dev/null)
$