会場が狭い
私はしばしばサブシェルを使って次の変更を行います。シェル実行環境、メインシェルに影響を与えないように。私はしばしばインタラクティブシェルでこれを行い、時にはスクリプトで行います。
タスク制御を有効または無効にすることは確かにそのようなタスクの1つであり、何らかの理由でプロセスのグループ化の詳細な制御が必要なときにこの機能を自由に使用してきました。
しかし、Bashユーザーとして、私はこれらの自由が最新バージョンで強化されたことを確認しました。 v4.3までは、ジョブ制御が許可され、対話型サブシェルで完全に機能していましたが、v4.4以降はそうではありませんでした。ここではまだ対話型サブシェルで動作しますが、完全には機能しません(下記参照)。スクリプトはまだうまく機能しますが、v5以降のジョブ制御に対する1つ以上の特定のユースケース(細かい処理などCtrl+C)が強化され、管理が容易になりました。スクリプト内のサブシェルでのみ..!
だから、疑わしく、いくつかの一般的なシェルでサンプルの総合テストを実行するのに時間を費やしました。すべてテストシェルのデフォルト(およびディストリビューションアップデート)バージョンを使用してUbuntu 19.04で行われました。
いくつかの背景
私は、、、およびdo bash
Honoryash
がサブシェルにあるのに対して、doはそうではないことを知りました。テストが終わって停止することさえ奇妙だった。mksh
zsh
set -m
dash
ksh
ksh
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
て提供しますが、そうしません。yash
mksh
zsh
実際、追加テストでは次のようになります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 end
Vimが終了した後。
しかし、前提で述べたように、bash
同じサンプルサブシェルを提供したときに競合が発生しました。まっすぐmksh
インタラクティブシェルのような無効なTPGIDを表示しますzsh
。この最終テストでは、yash
すべてが期待どおりに機能しました。
最も重要なのは、zsh -c
andが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とは異なります。bash
dash
set -m
mksh
ksh
zsh
最後に私の質問に戻って
横に本質的に関連するプログラミングの複雑さは、タスク制御が実際にサブシェル1でサポートされているという意味ですか?たぶんスクリプト2の内部にもありますか? (または:ここで私が見なかったものは何ですか?)
1 POSIXシェル実行環境禁止も施行もされないようです。
2から抜粋POSIXの説明set
: "set -m
オプション[...]は、デフォルトではシェルスクリプトアプリケーションではなく対話型の使用のためのものです。"