행사장이 협소해요
나는 종종 서브쉘을 사용하여 다음과 같은 변경을 수행합니다.쉘 실행 환경, 메인 쉘에 영향을 미치지 않도록. 나는 종종 대화형 셸에서 이 작업을 수행하고 때로는 스크립트에서 수행합니다.
작업 제어를 활성화하거나 비활성화하는 것은 확실히 그러한 작업 중 하나이며, 어떤 이유로든 프로세스 그룹화에 대한 세부적인 제어가 필요할 때 이 기능을 자유롭게 사용해 왔습니다.
그러나 Bash 사용자로서 저는 이러한 자유가 최신 버전에서 강화되었음을 확인했습니다. v4.3까지는 작업 제어가 허용되고 대화형 서브셸에서 완전히 작동했지만 v4.4 이후로는 그렇지 않았습니다. 여기에서는 여전히 대화형 하위 셸에서 작동하지만 완전히 작동하지는 않습니다(아래 참조). 스크립트에서는 여전히 잘 작동하지만, v5 이후 작업 제어에 대한 하나 이상의 특정 사용 사례(예: 세밀한 처리 Ctrl+C)가 강화되어 관리가 더 쉬워졌습니다.스크립트 내의 하위 쉘에서만..!
그래서 의심스러워서 일부 일반 셸에서 샘플 종합 테스트를 실행하는 데 시간을 보냈습니다. 모두 테스트 셸의 기본(및 배포판 업데이트) 버전을 사용하여 Ubuntu 19.04에서 수행되었습니다.
일부 배경
나는 bash
, yash
, mksh
및 zsh
do Honor가 set -m
서브셸에 있는 반면 dash
및 ksh
do는 그렇지 않다는 것을 알았습니다. 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
옵션 [...]은 기본적으로 쉘 스크립트 응용 프로그램이 아닌 대화형 사용을 위한 것입니다."