
によると:
{}
{ list; }
中かっこの間にコマンドリストを配置すると、そのリストは現在のシェルのコンテキストで実行されます。サブシェルは作成されません。。
ps
実際の効果を見るために使用されます
これは、コマンドラインから直接実行されるプロセスパイプラインのプロセス階層です。 4398はログインシェルのPIDです。
sleep 2 | ps -H;
PID TTY TIME CMD
4398 pts/23 00:00:00 bash
29696 pts/23 00:00:00 sleep
29697 pts/23 00:00:00 ps
次に、コマンドラインで直接実行される中括弧間のプロセスパイプラインのプロセス階層に従います。 4398はログインシェルのPIDです。上記の階層に似ており、すべてが現在シェルコンテキストで実行されていることを証明しています。:
{ sleep 2 | ps -H; }
PID TTY TIME CMD
4398 pts/23 00:00:00 bash
29588 pts/23 00:00:00 sleep
29589 pts/23 00:00:00 ps
これは、パイプライン自体が中かっこ内に配置されたときのプロセス階層ですsleep
(したがって、合計2つのレベルの中かっこがあります)。
{ { sleep 2; } | ps -H; }
PID TTY TIME CMD
4398 pts/23 00:00:00 bash
29869 pts/23 00:00:00 bash
29871 pts/23 00:00:00 sleep
29870 pts/23 00:00:00 ps
ドキュメントに中括弧間のコマンドが現在シェルのコンテキストで実行されていることが示されていますが、3bash
番目のケースで実行するサブシェルを作成する必要があるのはなぜですか?sleep
答え1
パイプでは、すべてのコマンドが異なるプロセス(stdout / stdinがパイプを介して接続されている)で同時に実行されます。
存在する
cmd1 | cmd2 | cmd3
3つのコマンドはすべて異なるプロセスで実行されるため、少なくとも2つのコマンドはサブプロセスで実行する必要があります。一部のシェルは現在のシェルプロセスでそのうちの1つを実行します(組み込みの場合、またはパイプがスクリプトread
の最後のコマンドである場合)、bash
独自の別々のプロセスで実行されます(lastpipe
最新bash
バージョンのオプションと特定の条件を除く)。 )。
{...}
グループコマンド。グループがパイプラインの一部である場合は、単純なコマンドなどの別々のプロセスで実行する必要があります。
存在する:
{ a; b "$?"; } | c
a; b "$?"
これを別のプロセスとして評価するにはシェルが必要なので、サブシェルが必要です。 forb
はグループで実行される最後のコマンドなので、forを分岐しないことでシェルを最適化できます。一部のシェルはこれを行うことができますが、明らかにそうではありませんbash
。
答え2
ネストされた中括弧は、新しいサブシェルを呼び出す必要がある追加のレベルの範囲を生成することを示すようです。 Bashの2番目のコピーを使用して、出力でこの効果を確認できますps -H
。
中かっこの最初のレベルで指定されたプロセスのみが、元のBashシェルの範囲内で実行されます。入れ子の中括弧は、独自の範囲の Bash シェル内で動作します。
はい
$ { { { sleep 20; } | sleep 20; } | ps -H; }
PID TTY TIME CMD
29190 pts/1 00:00:00 bash
5012 pts/1 00:00:00 bash
5014 pts/1 00:00:00 bash
5016 pts/1 00:00:00 sleep
5015 pts/1 00:00:00 sleep
5013 pts/1 00:00:00 ps
| ps -H
ネストされた中かっこを表示できるように、ミックスから取り出してps auxf | less
他のシェルで実行できます。
saml 29190 0.0 0.0 117056 3004 pts/1 Ss 13:39 0:00 \_ bash
saml 5191 0.0 0.0 117056 2336 pts/1 S+ 14:42 0:00 | \_ bash
saml 5193 0.0 0.0 107892 512 pts/1 S+ 14:42 0:00 | | \_ sleep 20
saml 5192 0.0 0.0 107892 508 pts/1 S+ 14:42 0:00 | \_ sleep 20
saml 5068 0.2 0.0 116824 3416 pts/6 Ss 14:42 0:00 \_ bash
saml 5195 0.0 0.0 115020 1272 pts/6 R+ 14:42 0:00 \_ ps auxf
saml 5196 0.0 0.0 110244 880 pts/6 S+ 14:42 0:00 \_ less
しかし、もっとたくさんあります!
パイプを取り出してこのコマンド形式を使用すると、実際に予想される内容を表示できます。
$ { { { sleep 10; } ; { sleep 10; } ; sleep 10; } } | watch "ps -H"
これで、結果監視ウィンドウで何が起こっているのかを2秒ごとに更新します。
これは最初のものですsleep 10
:
PID TTY TIME CMD
29190 pts/1 00:00:00 bash
5676 pts/1 00:00:00 bash
5678 pts/1 00:00:00 sleep
5677 pts/1 00:00:00 watch
5681 pts/1 00:00:00 watch
5682 pts/1 00:00:00 ps
これは2番目ですsleep 10
。
PID TTY TIME CMD
29190 pts/1 00:00:00 bash
5676 pts/1 00:00:00 bash
5691 pts/1 00:00:00 sleep
5677 pts/1 00:00:00 watch
5694 pts/1 00:00:00 watch
5695 pts/1 00:00:00 ps
これは3番目ですsleep 10
。
PID TTY TIME CMD
29190 pts/1 00:00:00 bash
5676 pts/1 00:00:00 bash
5704 pts/1 00:00:00 sleep
5677 pts/1 00:00:00 watch
5710 pts/1 00:00:00 watch
5711 pts/1 00:00:00 ps
異なるブレースネストレベルで呼び出されたにもかかわらず、3つのスリープモードは実際にはBashのPID 5676内に残ります。だからあなたの問題は| ps -H
。
結論として
(例:パイプ)を使用する| ps -H
と追加のサブシェルが生成されるため、何が起こっているのかを尋ねるときにその方法を使用しないでください。
答え3
私はテスト結果を公開します。これにより、bashは次の場合にグループコマンドのサブシェルを生成すると結論付けます。ただパイプラインの一部である場合、サブシェルでも呼び出される関数を呼び出すのと同じです。
$ { A=1; { A=2; sleep 2; } ; echo $A; }
2
$ { A=1; { A=2; sleep 2; } | sleep 1; echo $A; }
1