Shell:パイプとティーを使用すると「冗長プロセス」が発生するのはなぜですか?

Shell:パイプとティーを使用すると「冗長プロセス」が発生するのはなぜですか?

私はbashプロセスについてよく知りませんが、パイプとtee

以下では、スクリプトパスがで置き換えられます$FOLDER

  • $FOLDER/DBB/myparent.ksh:

    echo "BEGIN $$ this is the parent process"
    $FOLDER/DBB/myChild.ksh
    echo "END $$ this is the parent process"
    
  • $FOLDER/DBB/mychild.ksh:

    function toto {
      echo " this is $$ child process "
      sleep 10
    }
    {
      echo " $$ go1 "
      toto 
      ptree $$
      echo " $$ go2 "
    } | tee myLog$$.log
    
  • を起動すると、myParent.ksh次のプロセスツリーが表示されます。

    28417 /usr/lib/ssh/sshd -R
      28531 -ksh
        41387 /bin/bash myParent.ksh
          41390 /bin/bash $FOLDER/DBB/myChild.ksh
            41391 /bin/bash $FOLDER/DBB/myChild.ksh
              41393 sleep 10
            41392 tee myLog41390.log
    
  • コンソール出力:

    BEGIN 52665 this is the parent process
    in myChild.ksh
     52680 go1
     this is 52680 child process
    20192 zsched
      21104 /usr/lib/ssh/sshd
        27882 /usr/lib/ssh/sshd -R
          28417 /usr/lib/ssh/sshd -R
            28531 -ksh
              52665 /bin/bash myParent.ksh
                52680 /bin/bash $FOLDER/DBB/myChild.ksh
                  52688 /bin/bash $FOLDER/DBB/myChild.ksh
                    61896 ptree 52680
                  52692 tee myLog52680.log
     52680 go2
    END 52665 this is the parent process
    

なぜ2つですか$FOLDER/DBB/myChild.ksh

答え1

シェルスクリプトにはサフィックスが付いていますが、プロセスツリーは.kshそのスクリプトが実際にbashシェルによって実行されることを示します。

私のDebian 11 man ksh(実際にはmkshMirBSD Kornシェル)では、次のように言います。

パイプ内のすべてのコマンドは別々のサブシェルで実行されます。これはPOSIXでは許可されていますが、最後のコマンドを除くすべてのコマンドは、サブシェルで実行されるAT&T UNIX kshの2つのバリエーションとは異なります。意味と解決策のための機能です。

そしてman bash言った:

パイプラインの各コマンドは、別々のプロセス(つまりサブシェルで)で実行されます。 [...]lastpipe組み込み機能を使用してこのオプションを有効にするとshopt(以下の説明を参照shopt)、パイプの最後の要素がシェルプロセスによって実行される可能性があります。

したがって、最初にプロセス#41390が実行を開始するプロセスですmyChild.ksh。パイプが見えるとき:

{
  echo " $$ go1 "
  toto 
  ptree $$
  echo " $$ go2 "
} | tee myLog$$.log

$$パイプを展開し、{#41391の複合コマンドのサブシェルプロセスをフォークします}

プロセス#41392は、内部ではなくコマンドを実行し、それを最適化として処理する必要があるサブシェルであっても、親exec()プロセス#41390によってtee直接fork()コマンド+ 'd'になってもよい。exec()どちらの場合も、同じ結果をもたらします。 #41392は、表示されているコマンドラインを変更するexec()操作を実行します。exec()ptree

一方、サブシェル#41391には複数のコマンドが実行されるため、プロセス#41391はサブシェルとしてのアイデンティティを維持します。実行する必要がある最後のコマンドはechoシェル内部コマンドであるため、サブシェルプロセスとしての寿命は終了します。そして、パイプライン実行を準備するとき、親#41390はすでに$$sを拡張しているため、サブシェル#41391のPIDは出力に表示されません。

関連情報