組み込みコマンドを使用するとシェルがフォークされますか?

組み込みコマンドを使用するとシェルがフォークされますか?

コマンドを実行すると、type typestdoutの結果が表示されます。

次に、次のコマンドを試してみます。

type type > abc.txt

abc.txtしたがって、このコマンドが同じプロセス(bash自体)で実行されると、ファイル記述子1はポイントしますabc.txtabc.txtabc.txt

ただし、結果は常に標準出力として印刷されます。これは、シェルの組み込みがフォークされたプロセスで実行されていることを意味しますか?

答え1

通常、コマンドをリダイレクトするためにシェルがしなければならないのは、子プロセスをフォークして子プロセスだけにリダイレクトしてから(親ファイル記述子は影響を受けません)、その中でコマンドを実行することです(親は待っている間)。 。

組み込みコマンド(または複合コマンドまたは関数...)の場合、フォークや実行はありません。ただし、リダイレクトされた組み込みコマンドが終了すると、ファイル記述子は以前の状態に戻ります。

この目的のために、シェルはリダイレクトを実行する前に、リダイレクトされたファイル記述子のコピーを別のファイル記述子に保存し、そのファイル記述子をO_CLOEXECフラグとして表示します(組み込み機能が同じコマンドをeval実行する場合command)。返されると、シェルはファイル記述子を復元します。

たとえば、次のコマンドを実行すると、次のようになります。

strace sh -c 'echo test > /dev/null; :'

表示される内容(関連項目のみを含む):

  • open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3:リダイレクトするファイルを開きます。
  • fcntl(1, F_DUPFD, 10) = 10:生のstdoutを最初の利用可能なfd> = 10(ここでは10)にコピーします。
  • fcntl(10, F_SETFD, FD_CLOEXEC) = 0:O_CLOEXEC フラグを設定します。
  • dup2(3, 1) = 1:リダイレクトされたファイルを標準出力に設定します。
  • close(3) = 0:もう必要ありません。
  • write(1, "test\n", 5) = 5:echo は実行され、標準出力に "test\n" を書き込みます (現在 /dev/null にリダイレクトされます)。
  • dup2(10, 1) = 1: 標準出力の復元
  • close(10) = 0:不要になったfd 10を閉じます。

Bourneシェルで複合コマンドをリダイレクトすると、ブランチが発生します(thenにa=0; { a=1; echo "$a"; } >&2; echo "$a"示されています)。この問題を解決するには、実際に上記の作業を手動で実行する必要があります。10

変える

while cmd1; do cmd2; i=`expr "$i" + 1`; done > file

あなたはこれをしなければなりません:

exec 3>&1 > file
while cmd1 3>&-; do cmd2 3>&-; i=`expr "$i" + 1 3>&-`; done
exec >&3 3>&-

( 3>&-fd には O_CLOEXEC フラグがないため、各コマンドごとに 1 つずつ)

以前のバージョンのBourneシェルでは、組み込みコマンドをリダイレクトできませんでした。 pdp11をエミュレートするUnix V7では:

$ eval a=1 > /tmp/x
illegal io
$ read a < /etc/passwd
illegal io

答え2

出力リダイレクト

ファイル記述子は標準出力ストリームを1表します。stdoutで出力リダイレクトを使用すると、type type > abc.txtシェルは書き込み用にファイルを開き、ターミナルデバイスではなく開いたファイルを指すようにabc.txtファイル記述子を変更します。1

ただし、このリダイレクトは次の場合にのみ機能します。現在のコマンド実行中なのでこれがいいえコマンドが分岐プロセス(またはサブシェル)で実行されることを意味します。

継続的なリダイレクト

リダイレクトを続行するには、exec組み込みシェルを使用してファイル記述子を変更できます。たとえば、連続コマンドの標準出力をリダイレクトするには、次のコマンドを実行します。

exec >abc.txt

すべてのコマンド出力がターミナルデバイスの代わりにファイルにリダイレクトされると、シェルセッションを使用するのは難しいので、このコマンドを実行するときは注意してください。 (ファイル記述子)が指す同じ装置にファイル記述子をリダイレクトすることで、stdoutファイル記述子を端末出力装置に復元することができます。stderr2

exec >&2

関連リソース

詳細については、次を参照してください。

答え3

コマンドが完了すると、入力ファイルはすぐに閉じて他のプロセスから書き込むことができ、ファイル記述子が解放され、子プロセスが終了します。

関連情報