コマンド置換、プロセス置換、パイプ、バックグラウンドジョブで実行すると、「jobs」と「dirs」が元のシェルと同じように出力されるのはなぜですか?

コマンド置換、プロセス置換、パイプ、バックグラウンドジョブで実行すると、「jobs」と「dirs」が元のシェルと同じように出力されるのはなぜですか?

私が正しい場合、コマンド置換、プロセス置換、パイプ、およびバックグラウンドタスクは、元のシェルではなくサブシェルで独自に指定されたコマンドを実行します。

ただし、コマンドがまたはjobsの場合、dirsその出力は元のシェルで直接実行されたときとまったく同じです。

echo $( jobs )

cat <(jobs)

jobs | less

echo $( dirs )

cat <(dirs)

dirs | less

dirs &

なぜそんなことですか?サブシェルがソースシェルからジョブスタックとディレクトリスタックを継承するのですか、それともこのサブシェルではなくソースjobsシェルdirsで実行されているのですか?

しかし、

jobs &

何も出力しません。なぜ他のコマンドと違うのですか?ありがとうございます。

関連サブシェルからスクリプトをインポートすると、スクリプトのコマンドは元のシェルの状態にアクセスできますか?

ベストアンサー1

この答えの最初の部分はと組み込まれているので、通常bashはサブシェルを呼び出す代わりに直接実行しますjobsdirs

$(jobs)パイプや命令置換()やプロセス置換()がある場合も同様である<(jobs)

jobs &バックグラウンドでコマンドを実行したり()明示的にサブシェルを要求した場合(.を使用)、そうでは( jobs )ありません。

これは質問の最後の部分を説明します。サブシェルで実行すると、jobsサブシェル自体のアクションが表示されます。

以下は、この概念をよく示す例です。

$ sleep 1001 &
[1] 15927
$ sleep 1002 &
[2] 15940
$ jobs
[1]-  Running                 sleep 1001 &
[2]+  Running                 sleep 1002 &
$ ( sleep 1003 & jobs )
[1]+  Running                 sleep 1003 &
$ jobs
[1]-  Running                 sleep 1001 &
[2]+  Running                 sleep 1002 &

jobsサブシェルで実行すると、そのサブシェルに対するアクションのみが表示されることがわかります(この場合).sleep 1003

ここで要約すると、問題の中間部分を解決する必要があります。これがdirs &(サブシェルで実行されているかのように( dirs ))Pushdスタックに保存されているディレクトリがまだ表示される理由です。

DIRSTACKこれは、シェルがディレクトリリストを特殊な配列変数としてエクスポートし、この変数がサブシェルから継承されるためであることがわかりました。 (詳細はDIRSTACK ここ.)

これがどのように機能するかを示す1つの方法は、サブシェルpushdで使用し、元のシェルのディレクトリスタックにどのように影響しないかを確認することです。

$ dirs
~
$ pushd ~/tmp
~/tmp ~
$ ( dirs; pushd / >/dev/null; dirs )
~/tmp ~
/ ~/tmp ~
$ dirs
~/tmp ~

私はこれがあなたが要求したすべての問題を解決しなければならないと思います。


修正するjobs | less:bashには、現在シェルでコマンドを実行できる特別な規定がありますjobs(他の組み込みコマンドはそうではありません)。

コードには、サブシェルを生成せずに実行し、出力を別のコマンドにパイプできるjobs_hackように、後でチェックされる変数にチェックが格納されています。jobs

バラよりこここの機能を実装するソースコードの関連部分を理解してください。 (バッシュ4.4から)

おすすめ記事