키 입력을 사용하여 Bash 스크립트에서 호출 시간 초과를 제거할 수 없는 이유는 무엇입니까?

키 입력을 사용하여 Bash 스크립트에서 호출 시간 초과를 제거할 수 없는 이유는 무엇입니까?

[편집: 이것은 생성된 모든 프로세스를 종료하는 방법을 묻는 다른 질문과 유사해 보입니다. 대답은 모두 pkill을 사용하는 것 같습니다. 그래서 내 질문의 핵심은 아마도: 스크립트에 의해 생성된 모든 프로세스에 Ctrl-C/Z를 전파하는 방법이 있습니까? ]

coreutils의 명령을 사용하여 SoX를 호출하는 경우(논의됨 rec)timeout여기), Bash 스크립트에서 호출되면 키 입력으로 이를 종료할 수 있는 방법이 없는 것 같습니다.

예:

timeout 10 rec test.wav

Ctrl... bash에서 + C또는 Ctrl+를 사용하여 종료할 수 있지만 Z스크립트 내에서 호출할 때는 그렇지 않습니다.

timeout 10 ping nowhere

Ctrl... bash에서 + C또는 Ctrl+ 로 종료될 수 있습니다 Z. +는 스크립트 내에서 실행될 때입니다 Ctrl.Z

프로세스 ID를 찾아서 종료할 수 있는데 표준 인터럽트 키 누르기를 사용할 수 없는 이유는 무엇입니까? 내 스크립트를 구성할 수 있는 방법이 있나요?

답변1

Ctrl+ 신호 키가 C포그라운드의 모든 프로세스에 신호를 보낼 때 까지 기다립니다.프로세스 그룹.

일반적으로 프로세스 그룹은 파이프입니다. 예를 들어 에서 head <somefile | sort실행 중인 프로세스 head와 실행 중인 프로세스는 sort쉘과 마찬가지로 동일한 프로세스 그룹에 있으므로 둘 다 신호를 받습니다. somecommand &백그라운드에서 작업을 실행하는 경우 ( ) 작업은 자체 프로세스 그룹에 있으므로 Ctrl+를 눌러도 C영향을 받지 않습니다.

프로그램 timeout은 자신을 자체 프로세스 그룹에 배치합니다. 소스 코드에서:

/* Ensure we're in our own group so all subprocesses can be killed.
   Note we don't just put the child in a separate group as
   then we would need to worry about foreground and background groups
   and propagating signals between them.  */
setpgid (0, 0);

시간 초과가 발생하면 timeout해당 그룹이 속한 프로세스 그룹을 종료하는 간단한 해결 방법을 수행하십시오. 자신을 별도의 프로세스 그룹에 넣었으므로 상위 프로세스는 해당 그룹에 속하지 않습니다. 여기에서 프로세스 그룹을 사용하면 하위 애플리케이션이 여러 프로세스로 분기되는 경우 모든 프로세스가 신호를 받게 됩니다.

timeout명령줄에서 직접 실행하고 +를 누르면 자식 Ctrl프로세스는 C결과 SIGINT를 받지만 부모의 대화형 셸은 그렇지 않습니다. 스크립트에서 호출되면 스크립트를 실행하는 셸만 신호를 받습니다. 다른 프로세스 그룹에 있기 때문에 신호를 받지 않습니다.timeouttimeouttimeouttimeout

내장 함수를 사용하여 쉘 스크립트에서 신호 처리기를 설정할 수 있습니다 trap. 불행히도 그렇게 간단하지 않습니다. 생각해 보세요:

#!/bin/sh
trap 'echo Interrupted at $(date)' INT
date
timeout 5 sleep 10
date

Ctrl2초 후에 +를 누르면 C여전히 5초 동안 기다린 후 "Interrupted" 메시지가 인쇄됩니다. 이는 백그라운드 작업이 활성화된 동안 쉘이 트랩 코드를 실행하지 않기 때문입니다.

이 문제를 해결하려면 백그라운드에서 작업을 실행하세요. 신호 처리기에서는 kill신호를 timeout프로세스 그룹 에 전달하기 위한 호출이 이루어집니다 .

#!/bin/sh
trap 'kill -INT -$pid' INT
timeout 5 sleep 10 &
pid=$!
wait $pid

답변2

Giles가 제공한 훌륭한 답변을 바탕으로 구축되었습니다. timeout 명령에는 전경 옵션이 있습니다. CTRL+C를 사용하면 timeout 명령이 종료됩니다.

#!/bin/sh
trap 'echo caught interrupt and exiting;exit' INT
date
timeout --foreground 5 sleep 10
date

답변3

기본적으로 Ctrl+는 신호를 C보내고 +Z는 신호를 보냅니다.SIGINTCtrlSIGTSTP

SIGTSTP프로세스를 중지하면 SIGCONT계속 진행됩니다.

이는 명령줄에서 분기된 포그라운드 프로세스에 작동합니다.

프로세스가 백그라운드 프로세스인 경우 해당 신호를 프로세스에 다르게 보내야 합니다. kill그렇게 할 것입니다. 이론적으로, 종료 시 "-" 연산자는 하위 프로세스에도 신호를 보내야 하지만 예상대로 작동하는 경우는 거의 없습니다.

추가 자료:유닉스 신호

관련 정보