서브쉘과 스크립트에서 작업 제어가 실제로 지원되어야 합니까?

서브쉘과 스크립트에서 작업 제어가 실제로 지원되어야 합니까?

행사장이 협소해요

나는 종종 서브쉘을 사용하여 다음과 같은 변경을 수행합니다.쉘 실행 환경, 메인 쉘에 영향을 미치지 않도록. 나는 종종 대화형 셸에서 이 작업을 수행하고 때로는 스크립트에서 수행합니다.

작업 제어를 활성화하거나 비활성화하는 것은 확실히 그러한 작업 중 하나이며, 어떤 이유로든 프로세스 그룹화에 대한 세부적인 제어가 필요할 때 이 기능을 자유롭게 사용해 왔습니다.

그러나 Bash 사용자로서 저는 이러한 자유가 최신 버전에서 강화되었음을 확인했습니다. v4.3까지는 작업 제어가 허용되고 대화형 서브셸에서 완전히 작동했지만 v4.4 이후로는 그렇지 않았습니다. 여기에서는 여전히 대화형 하위 셸에서 작동하지만 완전히 작동하지는 않습니다(아래 참조). 스크립트에서는 여전히 잘 작동하지만, v5 이후 작업 제어에 대한 하나 이상의 특정 사용 사례(예: 세밀한 처리 Ctrl+C)가 강화되어 관리가 더 쉬워졌습니다.스크립트 내의 하위 쉘에서만..!

그래서 의심스러워서 일부 일반 셸에서 샘플 종합 테스트를 실행하는 데 시간을 보냈습니다. 모두 테스트 셸의 기본(및 배포판 업데이트) 버전을 사용하여 Ubuntu 19.04에서 수행되었습니다.

일부 배경

나는 bash, yash, mkshzshdo Honor가 set -m서브셸에 있는 반면 dashkshdo는 그렇지 않다는 것을 알았습니다. 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하고 제공 하지만 그렇게 하지 않습니다.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
$

반대로, bashyash모든 작업을 올바르게 수행합니다. 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옵션 [...]은 기본적으로 쉘 스크립트 응용 프로그램이 아닌 대화형 사용을 위한 것입니다."

관련 정보