이해하다
Bash가 명령이 완료되기를 기다리는 경우트랩이 설정되었다는 신호를 받으면 명령이 완료될 때까지 트랩이 실행되지 않습니다.
Bash가 wait 내장 함수를 통해 비동기 명령을 기다리는 경우, 트랩을 설정한 신호를 수신하면 내장된 대기가 128보다 큰 종료 상태로 즉시 반환된 다음 즉시 트랩을 실행하게 됩니다.
Bash 매뉴얼에 따르면 다음 명령을 실행합니다.
두 가지 예 모두에서 SIGINT(Ctrl-C와 함께 전송)는 포그라운드 작업(인용문의 첫 번째 사례)과 백그라운드 작업(인용문의 두 번째 사례)이 완료될 때까지 기다리지 않고 즉시 종료합니다.
인용문의 첫 번째 문장은 Bash가 포그라운드 작업을 실행하고 signal 을 받으면 명령이 완료될 때까지
SIGINT
신호의 트랩이SIGINT
설정된 후 실행된다는 의미입니까? 의 경우,첫 번째 예에서ctrl-C
포그라운드 작업이 완료되기 직전에 존재하는 이유는 무엇입니까?$ sleep 10000 # a foreground job ^C $ sleep 10000 & # a background job [1] 21219 $ wait 21219 ^C $ echo $? 130
무엇인가요"트랩이 설치되었다는 신호" 의미는,
arg
지정된 트랩을 통과한 신호trap arg sigspec
또는무시되지 않은 신호, 또는
트랩이 기본 트랩이 아닌 신호입니까?
Part 1의 예에서는 SIGINT에 대한 트랩을 설정하지 않았으므로 신호에 기본 핸들러(실행 루프가 중단됨)가 있었습니다. 는 기본 핸들러를 사용한 신호이것이 함정을 설치한 것으로 간주됩니까?
함정을 설치했어요
SIGINT
하지만ctrl-C
완료되기 전에 다음 명령이 종료됩니다. 그렇다면 이것은 제가 인용한 첫 번째 문장과 반대되는 것입니까?$ trap "echo You hit control-C!" INT $ bash -c 'sleep 10; echo "$?"' ^C $
함정을 설치하기 전에
SIGINT
,ctrl-C
또한 완료되기 전에 동일한 명령이 종료됩니다. 그렇다면 이것은 제가 인용한 첫 번째 문장과 반대되는 것입니까?$ bash -c 'sleep 10; echo "$?"' ^C
인용문의 두 문장이 무엇을 의미하는지 설명하기 위해 몇 가지 예를 들어주실 수 있나요?
감사해요.
답변1
"갇힌 신호"는 무엇을 의미합니까?
이는 핸들러 코드가 비어 있지 않은 경우(를 사용하여) 정의된 핸들러가 있는 신호입니다. trap 'handling code' SIG
이렇게 하면 신호가 무시됩니다.
따라서 기본 구성의 신호는 트랩된 신호가 아닙니다. 게시물의 인용문 중 일부는 기본 구성의 신호에도 적용됩니다.함정을 실행하다, 트랩이 정의되어 있지 않기 때문입니다.
매뉴얼에서는 신호 전달에 대해 설명합니다.껍질을 벗기다, 해당 쉘에서 실행하는 명령이 아닙니다.
1.
Bash가 명령이 완료되기를 기다리는 경우트랩이 설정되었다는 신호를 받으면 명령이 완료될 때까지 트랩이 실행되지 않습니다.
(1)
첫 번째 예에서 ctrl-C로 인해 포그라운드 작업이 완료되기 직전에 종료되는 이유는 무엇입니까?
sleep 10
대화형 쉘의 프롬프트에서 실행 중인 경우, 쉘은 작업을전망( ioctl()
tty 장치의 프로세스 그룹을 통해 어떤 프로세스 그룹이 전경 프로세스 그룹인지 터미널 회선 규칙에 알려줌)SIGINT 만 sleep
수신되며 ^C
대화형 쉘은 수신되지 않습니다., 따라서 이 동작을 테스트하는 것은 쓸모가 없습니다.
상위 셸은 대화형이므로 해당 프로세스가 포그라운드 프로세스 그룹에 속하지 않기 때문에 SIGINT를 받지 않습니다.
각 명령은 원하는대로 신호를 처리할 수 있습니다.
sleep
SIGINT에 대해 특별한 작업이 수행되지 않으므로 시작 시 SIGINT가 무시되지 않는 한 기본 구성(종료)이 획득됩니다.
(2)sleep 10
비대화형 쉘에서 실행 중인 경우,
bash -c 'sleep 10; echo "$?"'
bash
비대화형 쉘과 쉘 모두 Ctrl-C 를 누르면 sleep
SIGINT 를 받습니다 .
bash
즉시 종료 하면 sleep
SIGINT 신호를 무시하거나 처리하는 경우 백그라운드에서 명령이 무인 상태로 실행될 수 있습니다. 그래서 대신
bash
대부분의 다른 껍질과 마찬가지로,조각명령을 기다리는 동안 신호(적어도 일부 신호)를 수신합니다.- 명령이 종료된 후 전송이 재개됩니다(실행 트랩). 이는 또한 트랩의 명령이 다른 명령과 동시에 실행되는 것을 방지합니다.
위의 예에서는 sleep
SIGINT가 종료되므로 bash
자체 SIGINT를 처리하는 데 시간이 오래 걸리지 않습니다(여기서는 trap
SIGINT를 추가하지 않았기 때문에 종료됩니다).
(3) 비대화형 쉘을 실행할 때 Ctrl+C를 누르십시오.
bash -c 'sh -c "trap \"\" INT; sleep 3"; echo "$?"'
( trap
SIGINT 없이) bash
SIGINT에 의해 종료되지 않습니다. bash
, 다른 쉘과 마찬가지로 SIGINT 및 SIGQUIT를 구체적으로 처리합니다. 그들은 구현기다렸다가 협력하여 종료하세요.에 설명된 행동https://www.cons.org/cracauer/sigint.html(약간의 성가심을 유발하는 것으로 알려져 있습니다.SIGINT 처리 명령을 호출하는 스크립트는 중단될 수 없습니다.^C
)
(4) 올바르게 테스트하려면 다음을 수행해야 합니다.비대화형으로 실행bash
저것SIGINT 트랩 세트그리고 전화해SIGINT 직후에 종료되지 않는 명령좋다:
bash -c 'trap "echo Ouch" INT; sh -c "trap \"\" INT; sleep 3"'
bash
sh
(뿐만 아니라 ) SIGINT를 기다리는 것은 sleep
(때문에) 무시되므로 SIGINT는 둘 중 하나를 trap "" INT
종료하지 않습니다 . SIGINT는 무시되지 않지만 반환될 때까지 처리가 지연됩니다. 표시되는 화면은 켜져 있는 것이 아니라 정상적인 종료 이후에 표시 됩니다.sleep
sh
bash
sh
Ouch
Ctrl+Csleep
sh
이 trap
명령은 실행되는 동일한 쉘에 대한 신호 트랩을 설정합니다. 따라서 trap
비대화형 쉘 외부와 상위 쉘 내에서 명령이 실행될 때,
$ trap "echo You hit control-C!" INT $ bash -c 'sleep 10; echo "$?"' ^C $
이는 비대화형 bash
이며 sleep
명령은 trap
상위 셸에서 상속되지 않습니다. 다른 명령이 실행되면 신호 처리기가 손실됩니다( execve()
처리기 코드를 포함하여 프로세스의 전체 주소 공간이 지워집니다). execve()
정의된 핸들러가 있는 신호가 기본 구성으로 복원되면 무시된 신호는 무시된 상태로 유지됩니다 . 또한 대부분의 쉘에서 trap
s는 서브쉘에서도 재설정됩니다.
2.
Bash가 wait 내장 함수를 통해 비동기 명령을 기다리는 경우, 트랩을 설정한 신호를 수신하면 내장된 대기가 128보다 큰 종료 상태로 즉시 반환된 다음 즉시 트랩을 실행하게 됩니다.
wait
명시적으로 사용하는 경우, wait
갇힌 신호(그리고 분명히 쉘을 완전히 죽이는 신호)에 의해 중단됩니다.
이것이 어렵게 만든다포착 신호가 있을 때 명령의 종료 상태를 안정적으로 가져옵니다.:
$ bash -c 'trap "echo Ouch" INT; sh -c "trap \"\" INT; sleep 10" & wait "$!"; echo "$?"'
^COuch
130
이 경우 SIGINT에 의해 sleep
살해 sh
되지 않았습니다(무시했기 때문입니다). 기다리는 동안 신호(SIGINT)가 수신되었기 때문에 종료 상태가 여전히 wait
반환 됩니다 . 종료 상태를 얻으려면 실제로 종료될 때까지 반복해야 합니다 .130
sh
wait "$!"
sh
sh