誰かが2つのコマンドの出力をファイルとして別のコマンドに渡す方法を尋ねたところ、以下の answer が得られました。
( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )
これを開梱する必要があります。
テキストファイルsome_file
があり、それをmain_command
への入力として渡したいとします。 main_command
は2つのファイルを入力として受け取ります。 main_command
をsome_file
とともに使用し、コマンドcmd2
の出力を使用する場合、その1つの方法は次のとおりです。
( cmd2 | ( main_command some_file /dev/fd/4 ) 4<&0 )
main_command some_file /dev/fd/4
です。これは、ファイルsome_file
と/dev/fd/4
を引数としてmain_command
に渡すだけです。4<&0
の部分は、stdin
がファイル記述子4
を指すことを示しています。cmd2 |
は、cmd2
の出力を次の入力に接続します。私の質問は次のとおりです。
編集:私の論理が正しければ、1と答える必要はないと言ったはずです。
これはかなり複雑なコマンドです。私は最後にあなたの質問に直接答えましたが、それまでのすべてはコマンド自体を解凍することです。私は包括的にしようとしたので、場所によっては必要以上に詳細があるかもしれません。
_( x y z )
_
現在のシェルから新しいシェルをフォークし、で_x y z
_を実行する(そして現在のシェルに戻る)ことを意味します。サブシェルは現在のサブシェルに関するすべてを継承しますが、別のプロセスです。つまり、サブシェルに入力をパイプで送信し、親に影響を与えない独自の環境変更を内部に含めることができます。
開いているすべてのファイルには、数値の「ファイル記述子」が関連付けられています。このコンテキストでの「ファイル」には、実際のファイル、ソケット、標準I/Oストリームなど、あらゆる種類の入力ストリームまたは出力ストリームが含まれます。番号は、 C read
function で直接使用できるハンドルであり、話しているストリームを識別し、オペレーティングシステムによって提供される対応するシステムコールと他のすべてのIO関数。
_4<&0
_ リダイレクトを実行します 標準入力ファイル記述子(0)をファイル記述子4として複製します。つまり、FD 0は4にコピーされ、その逆ではありません。この場合、リダイレクトに先行するサブシェルの開いているファイルを変更しています。今のところ、それは入力ストリームの別の「名前」を作成しているだけです。ただし、重要な部分は、2つの名前がその後互いに独立していることです。FD0が別のものを参照するように変更され、2つが分岐した場合でも、FD4は常に同じストリームを参照します。
_/dev/fd/4
_は、プログラムが独自の開いているファイル記述子にアクセスするための(非標準の)方法です。 Linuxでは、これは_/proc/self/fd
_へのシンボリックリンクであり、現在のプロセスのファイル記述子テーブルを具体化します。プログラムはopen("/dev/fd/4", O_RDONLY)
を実行して、このプログラムがFD 4に持つストリーム(_4
_自体など)を参照するファイルハンドルを取得できます。プログラムに関する限り、これは他のファイルと同じように開いたり、閉じたり、読み取ったりできる通常のファイルです。開いているファイル記述子はサブプロセスによって継承されるため、_main_command
_はその内部のサブシェルと同じファイル記述子4を持ち、_/dev/fd/4
_もそこで機能します。
_cmd2 | x
_は_cmd2
_を実行し、その標準出力をx
の標準入力(またはFD 0)に接続します。コマンドでは、x
はサブシェル式です。
私たちの全体的なコマンド
_cmd2 | ( main_command /dev/fd/4 ) 4<&0
_
次に、3つの主要な部分があります。
cmd2
_を実行し、その出力を_( main_command /dev/fd/4 ) 4<&0
_にパイプします。4
_を_0
_の_( main_command /dev/fd/4 )
_(標準入力)で識別されるストリームの別の名前にします。main_command
_を指定して_/dev/fd/4
_を実行します。これは、(おそらく)ファイルとして開かれ、そこから読み取られ、_cmd2
_の出力を取得します。最終的な効果は、_main_command
_が開くことができるパス名引数を取得し、_cmd2
_の出力を読み取ることができることです。これは、Bashプロセス置換main_command <(cmd2)
の場合とまったく同じです。実際、引数として_/dev/fd/63
_を指定する可能性があります。それ以外の場合は、内部で非常によく似ています。
完全なコマンドについて
_( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )
_
サブシェルをネストしました。これは、標準入力の2つのコピーを作成するためですが、2つの異なる標準入力です。1つは_cmd1
_の出力です。大きい方のサブシェルにパイプされた後にFD3に送られ、もう1つは_cmd2
_の出力であり、最も内側のサブシェルにパイプされた後にFD4に入れられます。 2つの_0
_は両方とも標準入力を参照しますが、各コマンドの標準入力は、異なるものがパイプされているため、区別されます。
それが問題の最も紛らわしい部分だと思います。各コマンド(ここでは、各サブシェル)には、独自の標準入力があり、_cmd1
_または_cmd2
_からパイプされ、その一意の標準入力ストリームは次のようにエイリアスされます。 _3
_または_4
_。これらの開いているファイル記述子は、サブシェルコマンドと子コマンドの次のレイヤーに継承されるため、標準入力が別のものを指している場合でも、最も内側のコマンドの_/dev/fd/3
_は外部で行ったのと同じことを指します。
外側の括弧は厳密には必須ではありませんが、一部のコマンドでは少し堅牢になり、おそらく良い習慣になります。内部のものは次のとおりです。これらは、独自のリダイレクトセットを内部に持つことができる新しいサブプロセスを作成するために使用され、独自の標準入力ストリームがパイプされます。
最も内側のリダイレクトは実際には冗長です。標準入力にそれ以上の変更が加えられていないため、_cmd2 | main_command /dev/fd/3 /dev/stdin
_も機能します。
質問に直接対処するには:
質問の最初にコマンドを解凍するにはどうすればよいですか?
開梱は、この時点までの投稿全体です。
括弧は何をしますか?
括弧はサブシェルを作成します。これは、入力をパイプするなど、他のコマンドと同じように使用できる独立したシェルプロセスですが、リダイレクトなどの通常のシェル操作を内部で実行できます。
より単純なコマンドの私の説明は正しいですか?
部分的に。 _4<&0
_は、ファイル記述子4がstdinを指し、重要なことに現在stdinと呼ばれているものを指していることを示しています-標準入力の概念を指していません。 _/dev/fd/4
_は、「すべてがファイルである」という意味の「ファイル」ですが、より具体的には、開いたときにFD4を返すパス名です。