bashの(コマンド)とコマンドの違い

bashの(コマンド)とコマンドの違い

キーワードstderrリダイレクトの問題と問題の標準的なソリューションを調査中に別の問題を発見しました。説明が提供されますbashtimeman bash(list) 複合コマンドはいリストはサブシェル環境で実行されます。。アプレットの実行でわかるように、単純な呼び出しを行い、コマンドラインとコマンドラインの間に違いがないhelloようです。system("ps -opid,ppid,comm")私はこれが私を驚かせた。しかし、コマンドが組み込みコマンドの場合には違いがあることを知っています。この場合、括弧がないと分岐は発生しませんが、組み込みコマンドの周りに括弧があると分岐が発生します。私は何を逃したことがありませんか?(./hello)./hello

18:59:13 -> echo $$
5323
19:34:30 -> ./hello
hello world from process ID 8657, parent ID 5323
  PID  PPID COMM
 5323  5322 -bash
 8657  5323 ./hello
19:42:34 -> (./hello)
hello world from process ID 8977, parent ID 5323
  PID  PPID COMM
 5323  5322 -bash
 8977  5323 ./hello
19:42:43 -> time (./hello)
hello world from process ID 8985, parent ID 8984
  PID  PPID COMM
 5323  5322 -bash
 8984  5323 -bash
 8985  8984 ./hello

real    0m0.021s
user    0m0.003s
sys 0m0.004s
19:42:53 -> (time ./hello)
hello world from process ID 9000, parent ID 8999
  PID  PPID COMM
 5323  5322 -bash
 8999  5323 -bash
 9000  8999 ./hello

real    0m0.030s
user    0m0.003s
sys 0m0.005s
19:43:05 ->

答え1

サブシェルは別々のプロセスで実行されるという保証はありません。これは一般的な実装です。

サブシェルの定義は、シェルがサブシェルが親シェルの状態を変更しないようにする必要があることです。サブシェルは、親シェルの変数、定義された関数、エイリアス、オプション、履歴、制限などに影響を与えることはできません。最も簡単な方法は、別のプロセスでサブシェルを実行することであるため、通常これが発生します。ただし、子シェルが親シェルのどの項目にも影響しないことを保証できる場合、シェルは別のプロセスを実行する必要はありません。

ほとんどのsh実装では、外部コマンドを実行する以外に何もしないサブシェルは2回分岐しません。

for sh in dash bash ksh93 mksh zsh; do printf "%6s " "$sh"; "$sh" -c '(perl -e "print getppid()"); echo " $$"'; done
  dash 945 945
  bash 947 947
 ksh93 949 949
  mksh 951 951
   zsh 953 953

より複雑なタスクを実行すると、bashはサブシェルをフォークし、外部コマンドを再度フォークします。一部の他のシェルは、(トラップがない限り)(サブ)シェルの最後のコマンドをフォークしません。

for sh in dash bash ksh93 mksh zsh; do printf "%6s " "$sh"; "$sh" -c '(true; perl -e "print getppid()"); echo " $$"'; done
  dash 1306 1306
  bash 1309 1308
 ksh93 1311 1311
  mksh 1314 1313
   zsh 1316 1316

ATT ksh( ksh93) は他のシェルよりも最適化されています。私が比較した5つのプログラムのうち、サブシェルで変化するデータを追跡するために、同じプロセスで別々のデータ構造を作成して最適化した唯一のプログラムでした。

for sh in dash bash ksh93 mksh zsh; do printf "%6s " "$sh"; "$sh" -c '(perl -e "print getppid()"; /bin/true); echo " $$"'; done
  dash 3082 3081
  bash 3085 3084
 ksh93 3088 3088
  mksh 3092 3091
   zsh 3096 3095

プロセス制限の変更など、ATT kshにサブシェル用のサブプロセスを作成させることもできます。

for sh in dash bash ksh93 mksh zsh; do printf "%6s " "$sh"; "$sh" -c '(ulimit -n 42; perl -e "print getppid()"; /bin/true); echo " $$"'; done
  dash 4504 4503
  bash 4507 4506
 ksh93 4511 4510
  mksh 4515 4514
   zsh 4519 4518

関連情報