web-dev-qa-db-ja.com

bashはCのfork()と同様のフォークをサポートしていますか?

ある時点でフォークしたいスクリプトがあるので、同じスクリプトの2つのコピーが実行されています。

たとえば、次のbashスクリプトが存在するようにします。

echo $$
do_fork()
echo $$

このbashスクリプトが本当に存在する場合、予想される出力は次のようになります。

<ProcessA PID>
<ProcessB PID>
<ProcessA PID>

または

<ProcessA PID>
<ProcessA PID>
<ProcessB PID>

この種の出力を取得したり、bashスクリプトにCのようなforkを実行させたりするために、「do_fork()」の代わりに配置できるものはありますか?

26
Cory Klein

はい。フォークのスペルは&です:

echo child & echo parent

混乱するかもしれませんが、$$はシェルプロセスのPIDではなく、originalシェルプロセスのPIDです。このようにすることのポイントは、$$がシェルスクリプトの特定のインスタンスの一意の識別子であるということです。これは、スクリプトの実行中に変更されず、同時に他の$$とは異なります。実行中のスクリプト。シェルプロセスの実際のPIDを取得する1つの方法は、sh -c 'echo $PPID'です。

シェルの制御フローはCと同じではありません。Cの場合、次のように記述します。

first(); fork(); second(); third();

シェルの同等物は

after_fork () { second; third; }
first; after_fork & after_fork

単純なシェル形式first; child & parentは、通常のCイディオムに対応しています

first(); if (fork()) parent(); else child();

&および$$は存在し、すべてのBourneスタイルのシェルと(t)cshでこのように動作します。 $PPIDは、元のBourne Shellには存在しませんでしたが、POSIXにあります(つまり、ash、bash、ksh、zshなどにあります)。

はい、それは subshel​​ls と呼ばれます。括弧内のシェルコードはサブシェル(フォーク)として実行されます。ただし、最初のシェルは通常、子が完了するのを待ちます。 &ターミネータを使用して非同期にすることができます。次のようなものを使って実際にそれを見てください:

#!/bin/bash

(sleep 2; echo "subsh 1")&
echo "topsh"

$ bash subsh.sh

10
Keith

これを行うネイティブbash(または私の知る限り、他の一般的な* nixシェル)の方法はありません。非同期で何かを行うフォークされたプロセスを生成する方法はたくさんありますが、fork()システムコールの正確なセマンティクスに従うものはないと思います。

典型的なアプローチは、トップレベルのスクリプトに、分割したい作業だけを実行するヘルパーを生成させることです。もし、するなら $0 $@ &または何でも、最初からやり直して、なんとかしてそれを理解する必要があります。

私は実際にそれを行うかもしれないいくつかの賢い方法を考え始めています...

しかし、私の頭がそれでうんざりする前に、私はかなり良いルールだと思います:シェルで何かを書こうとしていて、それが巧妙なトリックでいっぱいになり、あなたが望んでいるならより多くの言語機能、実際のプログラミング言語に切り替える時間

7
mattdm