サブシェルとスクリプトでジョブ制御を実際にサポートする必要がありますか?

サブシェルとスクリプトでジョブ制御を実際にサポートする必要がありますか?

会場が狭い

私はしばしばサブシェルを使って次の変更を行います。シェル実行環境、メインシェルに影響を与えないように。私はしばしばインタラクティブシェルでこれを行い、時にはスクリプトで行います。

タスク制御を有効または無効にすることは確かにそのようなタスクの1つであり、何らかの理由でプロセスのグループ化の詳細な制御が必要なときにこの機能を自由に使用してきました。

しかし、Bashユーザーとして、私はこれらの自由が最新バージョンで強化されたことを確認しました。 v4.3までは、ジョブ制御が許可され、対話型サブシェルで完全に機能していましたが、v4.4以降はそうではありませんでした。ここではまだ対話型サブシェルで動作しますが、完全には機能しません(下記参照)。スクリプトはまだうまく機能しますが、v5以降のジョブ制御に対する1つ以上の特定のユースケース(細かい処理などCtrl+C)が強化され、管理が容易になりました。スクリプト内のサブシェルでのみ..!

だから、疑わしく、いくつかの一般的なシェルでサンプルの総合テストを実行するのに時間を費やしました。すべてテストシェルのデフォルト(およびディストリビューションアップデート)バージョンを使用してUbuntu 19.04で行われました。

いくつかの背景

私は、、、およびdo bashHonoryashがサブシェルにあるのに対して、doはそうではないことを知りました。テストが終わって停止することさえ奇妙だった。mkshzshset -mdashkshksh

TL;博士:以下は、私が説明した長いプレゼンテーションセッションの内容です。

$ bash -c 'echo start; (set -bm; echo $-; sleep 3 & ps -s '$$' -o pid,ppid,pgid,tpgid,sid,s,cmd; wait); echo end'
start
bhmBc
   PID   PPID   PGID  TPGID    SID S CMD
 30147  30146  30147  31244  30147 S -bash
 31241  30147  31241  31244  30147 S bash -c echo start; (set -bm; echo $-; sleep 3 & ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s
 31242  31241  31241  31244  30147 S bash -c echo start; (set -bm; echo $-; sleep 3 & ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s
 31243  31242  31243  31244  30147 S sleep 3
 31244  31242  31244  31244  30147 R ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s,cmd
[1]+  Done                    sleep 3
end
$
$
$ dash -c 'echo start; (set -bm; echo $-; sleep 3 & ps -s '$$' -o pid,ppid,pgid,tpgid,sid,s,cmd; wait); echo end'
start
bm
   PID   PPID   PGID  TPGID    SID S CMD
 30147  30146  30147  31245  30147 S -bash
 31245  30147  31245  31245  30147 S dash -c echo start; (set -bm; echo $-; sleep 3 & ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s
 31246  31245  31245  31245  30147 S dash -c echo start; (set -bm; echo $-; sleep 3 & ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s
 31247  31246  31245  31245  30147 S sleep 3
 31248  31246  31245  31245  30147 R ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s,cmd
end     # «« 3 seconds correctly elapsed before getting here
$
$
$ yash -c 'echo start; (set -bm; echo $-; sleep 3 & ps -s '$$' -o pid,ppid,pgid,tpgid,sid,s,cmd; wait); echo end'
start
cmb
[1] + Running              sleep 3
   PID   PPID   PGID  TPGID    SID S CMD
 30147  30146  30147  31252  30147 S -bash
 31249  30147  31249  31252  30147 S yash -c echo start; (set -bm; echo $-; sleep 3 & ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s
 31250  31249  31249  31252  30147 S yash -c echo start; (set -bm; echo $-; sleep 3 & ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s
 31251  31250  31251  31252  30147 S sleep 3
 31252  31250  31252  31252  30147 R ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s,cmd
[1] + Done                 sleep 3
end
$
$
$ mksh -c 'echo start; (set -bm; echo $-; sleep 3 & ps -s '$$' -o pid,ppid,pgid,tpgid,sid,s,cmd; wait); echo end'
start
mbhc
   PID   PPID   PGID  TPGID    SID S CMD
 30147  30146  30147  31253  30147 S -bash
 31253  30147  31253  31253  30147 S mksh -c echo start; (set -bm; echo $-; sleep 3 & ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s
 31254  31253  31253  31253  30147 S mksh -c echo start; (set -bm; echo $-; sleep 3 & ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s
 31255  31254  31255  31253  30147 S mksh -c echo start; (set -bm; echo $-; sleep 3 & ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s
 31256  31254  31256  31253  30147 R ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s,cmd
[1] + Done                 \sleep 3
end
$
$
$ ksh -c 'echo start; (set -bm; echo $-; sleep 3 & ps -s '$$' -o pid,ppid,pgid,tpgid,sid,s,cmd; wait); echo end'
start
cbhmsB
   PID   PPID   PGID  TPGID    SID S CMD
 30147  30146  30147  31258  30147 S -bash
 31257  30147  31257  31258  30147 S ksh -c echo start; (set -bm; echo $-; sleep 3 & ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s,
 31258  31257  31257  31258  30147 S ksh -c echo start; (set -bm; echo $-; sleep 3 & ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s,
 31259  31258  31257  31258  30147 S ksh -c echo start; (set -bm; echo $-; sleep 3 & ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s,
 31260  31258  31257  31258  30147 R ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s,cmd
   # —— 3 seconds correctly elapsed on this empty line (which is *not* by me) ——
[1]+  Stopped                 ksh -c 'echo start; (set -bm; echo $-; sleep 3 & ps -s '$$' -o pid,ppid,pgid,tpgid,sid,s,cmd; wait); echo end'
$
$
$ fg   # «« had to get rid of Stopped `ksh` from my login shell
ksh -c 'echo start; (set -bm; echo $-; sleep 3 & ps -s '$$' -o pid,ppid,pgid,tpgid,sid,s,cmd; wait); echo end'
end
$
$
$ zsh -c 'echo start; (set -5m; echo $-; sleep 3 & ps -s '$$' -o pid,ppid,pgid,tpgid,sid,s,cmd; wait); echo end'
start
569Xm
   PID   PPID   PGID  TPGID    SID S CMD
 30147  30146  30147  31261  30147 S -bash
 31261  30147  31261  31261  30147 S zsh -c echo start; (set -5m; echo $-; sleep 3 & ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s,
 31262  31261  31261  31261  30147 S zsh -c echo start; (set -5m; echo $-; sleep 3 & ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s,
 31263  31262  31263  31261  30147 S sleep 3
 31264  31262  31264  31261  30147 R ps -s 30147 -o pid,ppid,pgid,tpgid,sid,s,cmd
end     # «« 3 seconds correctly elapsed before getting here
$

上記の各方法のTPGID値に応じて、psシェルはサブシェル内で完全に機能するジョブ制御環境のみをset -m尊重しbashて提供しますが、そうしません。yashmkshzsh

実際、追加テストでは次のようになりますmksh

$ mksh -c 'echo start; (set -bm; echo $-; vim); echo end'
start
mbhc
Vim: Caught deadly signal HUP
Vim: Finished.
   «« —— cursor stopped here. Then I hit Return ——
2R1: command not found
95: command not found
0c: command not found
$

しかしzsh

$ zsh -c 'echo start; (set -5m; echo $-; vim); echo end'
start
569Xm      «« —— cursor stopped here. Then I `killall zsh` from another terminal ——
Terminated
$ Vim: Caught deadly signal HUP
Vim: Finished.
   «« —— cursor stopped here. Then I hit Return ——
2R1: command not found
95: command not found
0c: command not found
$

もちろん、vim親を殺す前には停止した状態ですzsh

$ ps -t 0 -o pid,ppid,pgid,tpgid,sid,s,cmd
   PID   PPID   PGID  TPGID    SID S CMD
 30147  30146  30147  31582  30147 S -bash
 31582  30147  31582  31582  30147 S zsh -c echo start; (set -5m; echo $-; vim); echo end
 31583  31582  31583  31582  30147 T vim
$
$ killall zsh
$

逆に、bashおよびyashすべての操作を正しく実行します。echo startそして$-、完全に利用可能な実行vim(カーソルキーとを含むCtrl+C)、そしてecho endVimが終了した後。

しかし、前提で述べたように、bash同じサンプルサブシェルを提供したときに競合が発生しました。まっすぐmkshインタラクティブシェルのような無効なTPGIDを表示しますzsh。この最終テストでは、yash すべてが期待どおりに機能しました。

最も重要なのは、zsh -candがmksh -c(つまり、非対話型で)いいえまあ、入れてもset -m 外部サブシェルはvim内部にのみ残ります。vim私がそれを脱いだときだけサブシェルでのみうまくいきますset -m。これはset -mスクリプトでもこれらのシェルでは機能しないことを意味します(実際には後でテストしましたが失敗しました)。


このテストは非常に混乱しているようで、上記のサンプルテストに誤った仮定があるかどうかはわかりません。だから私はさらに(おそらく)無害なものを試しました。

#!/usr/bin/zsh

set -m
echo start
echo $-
tr '[a-z]' '[A-Z]'
echo end

もちろんいいえ処置:tr すぐに停止し、TPGIDは続行されますzsh

これはand(もちろん全く尊重しません)と連携yashしますが、andではうまくいきません。ただし、各結果はandとは異なります。bashdashset -mmkshkshzsh


最後に私の質問に戻って

横に本質的に関連するプログラミングの複雑さは、タスク制御が実際にサブシェル1でサポートされているという意味ですか?たぶんスクリプト2の内部にもありますか? (または:ここで私が見なかったものは何ですか?)

1 POSIXシェル実行環境禁止も施行もされないようです。

2から抜粋POSIXの説明set: "set -mオプション[...]は、デフォルトではシェルスクリプトアプリケーションではなく対話型の使用のためのものです。"

ベストアンサー1

おすすめ記事