「echo 123>(cat)」出力に「/dev/fd/63」があるのはなぜですか?

「echo 123>(cat)」出力に「/dev/fd/63」があるのはなぜですか?
$ 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

したがって、あなたの質問に答えると、echo2つのパラメータ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)//とは対照的にkshbashこれはzshプロセスです。置換

cmd1 >(cmd2)にはyashwait がないので厳密に等しくないので、次のようなものを見つける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

ただし、bashforのプロセスリダイレクトと同様に、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つのコマンドラインで複数の置換を実行できるという点でより柔軟ですが、名前でファイルを開くにはデフォルトのコマンドが必要です(代わりにcatecho

次の手順を実行して、プロセス置換を含むパイプラインをシミュレートできます。

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

関連情報