Ctrl+C
사용자에게 확인을 요청하는 신호를 잡으려고 합니다 . 캡처 부분은 잘 작동합니다. 그러나 일단 신호가 포착되면 정상적인 실행으로 돌아가지 않습니다. 대신 스크립트를 종료합니다. 사용자가 아니오를 눌렀을 때 실행을 다시 시작하게 하려면 어떻게 해야 합니까?
이게 내 코드야
hell()
{
echo "Do you want to quit? Press 1 for yes and 0 for no";
read n;
if [ $n == 1 ]; then
exit 1;
fi
}
trap "hell" SIGINT
find /
답변1
무슨 일이에요
Ctrl+를 누르면 신호가 전체로 전달됩니다 C.SIGINT
포그라운드 프로세스 그룹. 여기서는 find
프로세스와 호출 쉘 프로세스 로 전송됩니다 . find
반응은 즉시 종료되는 것이고, 쉘 반응은 트랩을 호출하는 것입니다.
트랩의 코드가 반환되면(즉, 호출되지 않음 exit
) 신호에 의해 중단된 명령 다음에 오는 명령으로 실행이 계속됩니다. 여기서는 명령 find
뒤에 스크립트가 끝나므로 어쨌든 스크립트가 즉시 종료됩니다. 그러나 다른 명령을 추가하면 입력 0과 1의 차이를 확인할 수 있습니다.
find /
echo "find returned $?"
하고 싶은 일을 하는 방법(하지만 해서는 안 될 수도 있음)
원하는 대로 할 수 있지만 내 대답의 이 부분은 실제 문제를 해결하는 것보다 쉘 프로그래밍을 발견하는 것에 관한 것입니다.
- 설계상 재시작 가능 신호는 쉘 스크립트와 같은 상대적으로 간단한 프로그램에서 일반적으로 기대하는 신호가 아닙니다. Ctrl+가 C스크립트를 종료할 것으로 예상 됩니다.
- 그러나 아래에서 볼 수 있듯이 이는 셸의 기능을 약간 확장합니다.
살인을 피하고 싶다면 find
,배경: find / &
. 그런 다음 사용wait
내장정상적으로 종료될 때까지 기다립니다. 신호는 wait
전파할 신호를 받을 때까지 루프에서 실행할 수 있는 내장 프로그램을 중단합니다. 그런 다음 kill
.
hell () {
echo "Do you want to quit? Press 1 for yes and 0 for no"
read n
if [ "$n" = 1 ]; then
# Kill the job if it's running, then exit
if [ -n "$job_pid" ]; then kill $job_pid; fi
exit 1
fi
}
job_pid=
trap "hell" SIGINT
# Start a demo job in the background
for i in 1 2 3 4 5; do date; sleep 1; done &
job_pid=$!
# Call wait in a loop; wait will return 0 if the job exits, and 128+$signum if interrupted by a signal.
while ! wait; do
echo "resuming wait"
done
job_pid=
echo last exit code: $?
이 접근 방식에는 셸에 다음과 같은 제한 사항이 있습니다.
- 경쟁 조건이 있습니다. 작업이 완료된 후 line 이전에 +를 누르면 Ctrl신호 처리기가 종료를 시도하지만 프로세스는 더 이상 존재하지 않습니다(심지어 수확되었으므로 좀비인 경우에도). ID가 이미 다른 프로세스에서 재사용되었을 수 있습니다. 이는 셸에서 쉽게 해결되지 않습니다(아마도 핸들러를 설정하여?).C
job_pid=
$jobpid
wait
SIGCHLD
wait $job_pid
이 양식은 일자리의 반환 상태가 필요한 경우 필요합니다 . 그러나 "신호에 의해 중단됨"과 "신호에 의해 작업이 종료됨"을 구별할 수 없습니다wait
("작업이 반환 상태 ≥ 128로 자체 종료됨"도 아니지만 이는 쉘 프로그래밍에서 일반적인 사실입니다).- 이는 여러 하위 작업으로 쉽게 확장되지 않습니다. 대부분의 쉘 구현의 기본을 넘어서면 트랩과 신호가 종종 놀라운 방식으로 작동한다는 점에 유의하십시오(ksh만이 이를 잘 수행합니다).
이러한 제한을 극복하려면 Perl이나 Python과 같은 고급 언어를 사용하세요.