誰かが2つのコマンドの出力をファイルとして別のコマンドに渡す方法を尋ね、彼らは次のような結果を得ました。回答次のような。
( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )
これを分解する必要があります。
some_file
に入力として渡すテキストファイルがあるとしますmain_command
。main_command
2つのファイルを入力として使用します。コマンドの出力main_command
と共に使用するには、1つの方法があります。some_file
cmd2
( 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は必要ないと言うべきです。
答え1
これはかなり複雑なコマンドです。最後にあなたの質問に直接答えますが、それ以前はunzipコマンド自体についてです。可能な限り包括的に説明しようとしたため、一部の場所では必要以上に詳細になる可能性があります。
( x y z )
新しいシェルが現在のシェルで作成され実行されたことをx y z
示します(次に現在のシェルに返されます)。サブシェルは現在のシェルからすべてを継承しますが、別々のプロセスです。つまり、親シェルに影響を与えずに内部で入力をパイプし、独自の環境を変更できます。
開いているすべてのファイルには、数字の「ファイル記述子」があります。と関連付けられる。この文書の「ファイル」には、実際のファイル、ソケット、および標準I / Oストリームを含むすべてのタイプの入力または出力ストリームが含まれています。この数字は次のものと直接比較できます。Cread
関数話しているストリームを識別し、そのシステムコールとオペレーティングシステムによって提供される他のすべてのIO機能を使用します。
4<&0
リダイレクトの実行標準入力ファイル記述子(0)をファイル記述子4に複製します。。これは意味するFD 0 が 4 にコピーされました。、その逆ではありません。この場合、リダイレクトの前にサブシェルのオープンファイルを変更します。現在、これは入力ストリームの別の「名前」を生成します。しかし、重要な部分は、2つの名前が互いに独立しているということです。 FD 0が異なるものを参照するように変更され、2つの名前が異なる場合でも、FD 4は常に同じストリームを参照します。
/dev/fd/4
プログラムが開いたファイル記述子にアクセスする(非標準)方法です。。 Linuxでは、/proc/self/fd
現在のプロセスのファイル記述子テーブルを具体化するシンボリックリンクです。プログラムはopen("/dev/fd/4", O_RDONLY)
、プログラムがFD 4によって所有されているストリーム(たとえばそれ4
自体)を参照するファイルハンドルを取得できます。プログラムに関する限り、これは他のファイルのように開いて閉じて読み取ることができる一般的なファイルです。開かれたファイル記述子は子プロセスによって継承されるため、子main_command
プロセスのファイル記述子4と同じファイル記述子4を持つため、/dev/fd/4
そこでも機能します。
cmd2 | x
cmd2
標準出力を実行し、標準入力(またはfd 0)に接続しますx
。コマンドには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
。
最終的な効果は、Bashプロセスの置き換えとまったく同じように、出力で開いてmain_command
読み取ることができるパス名引数を取得することです。実際、これは引数として提供でき、そうでない場合は内部処理は非常に似ています。cmd2
main_command <(cmd2)
/dev/fd/63
完全なコマンドの場合
( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )
私たちは入れ子になったサブシェルを持っています。これは、標準入力の2つのコピーを作成したいからです。2つの異なる標準入力:1つはより大きなサブシェルにパイプされた後にFD 3に入る出力cmd1
、もう1つはcmd2
最も内側のサブシェルにパイプされた後にFD 4に入る出力です。どちら0
のコマンドも標準入力を参照しますが、異なる入力をパイプしたため、各コマンドの標準入力は異なります。
私はこれがこの質問の中で最も混乱している部分だと思います。すべてのコマンド(ここですべてのサブシェル)にそれcmd1
またはからパイプされた標準入力cmd2
とその固有の標準入力ストリームは、またはに3
エイリアスされます4
。これらのオープンファイル記述子は、次のレベルのサブシェルとサブコマンドによって継承されるため、/dev/fd/3
標準入力が別のものを指していても、最も内側のコマンドは外部で実行するのと同じ操作を参照します。
外部カッコは、いくつかのコマンドに対してやや強力で良い習慣になるかもしれませんが、必ずしも必要ではありません。内部的には:独自のリダイレクトセットを持つことができるだけでなく、独自の標準入力ストリームをパイプ処理できる新しいサブプロセスを作成するためにも使用されます。
最も内側のリダイレクトは実際に重複しています。cmd2 | main_command /dev/fd/3 /dev/stdin
標準入力が変更されなくなったため動作します。
問題を直接解決するには:
-
質問の冒頭にあるコマンドを解凍するにはどうすればよいですか?
これまでの投稿はアンパックが全てです。
-
括弧は何をしますか?
角かっこは、入力パイピングを含む他のコマンドのように使用できますが、内部でリダイレクトなどの一般的なシェル操作を実行できる別のシェルプロセスであるサブシェルを生成します。
-
より簡単なコマンドの説明は正しいですか?
部分的に。
4<&0
ファイル記述子4がstdinを指すと仮定すると、重要なことは今stdinと呼ばれます- 標準入力の概念ではありません。/dev/fd/4
「すべてがファイルの意味です」から「ファイル」ですが、より具体的に言えば、開いたときにFD 4に戻るパス名です。