적절한 종료를 위해 ctrl+C를 감지하는 사용자 정의 명령줄 소프트웨어(예: loopHelloWorld)를 고려해보세요. 을 잃지 않고 답변을 파이프하는 방법은 무엇입니까 Ctrl+C
?
$ loopHelloWorld
- Ctrl+C to nicely shutdown
그러나 파이프를 사용하면 파이프가 제대로 종료되지 않고 소프트웨어를 종료합니다.
$ loopHelloWorld |
while IFS= read -r line; do
echo "$line"
done
예
ping example.com |
while IFS= read -r line; do
echo "$line"
done
답변1
Ctrl+C파이프라인의 모든 프로세스에 SIGINT가 전송됩니다(모두 대화형 셸의 포그라운드 작업에 해당하는 동일한 프로세스 그룹에서 실행되기 때문입니다).
그래서:
loopHelloWorld |
while IFS= read -r line; do
echo "$line"
done
실행 중인 프로세스 와 루프를 loopHelloWorld
실행하는 하위 쉘을 실행하는 프로세스 모두 .while
SIGINT
loopHelloWorld
stdout에 메시지를 쓰면 파이프 Ctrl+C to nicely shutdown
에도 기록됩니다. 그렇다면~ 후에다른 쪽 끝에 있는 서브쉘은 이미 죽었고, loopHelloWorld
그러면또한처리해야 하는 SIGPIPE를 받습니다.
여기서는 명령의 일반 출력이 아니기 때문에 해당 메시지를 stderr에 작성해야 합니다( ping
단, 예제에는 적용되지 않음). 그러면 파이프를 통과하지 못할 것입니다.
또는 while 루프를 실행하는 서브셸이 SIGINT를 무시하도록 하여 loopHelloWorld
SIGINT 이후의 출력을 계속 읽을 수 있습니다.
loopHelloWorld | (
trap '' INT
while IFS= read -r line; do
printf '%s\n' "$line"
done
)
그러나 를 누르면 파이프라인의 종료 상태가 0이 됩니다 Ctrl+C.
특정 예에 대한 또 다른 옵션은 대신 zsh
또는 를 사용하는 것입니다 . 해당 셸에서 루프는 기본 셸 프로세스에서 실행되므로 SIGINT의 영향을 받지 않습니다.ksh93
bash
while
이는 포그라운드 프로세스 그룹에서 loopHelloWorld | cat
어디에서 실행 cat
되는지 에 대해서는 도움이 되지 않습니다 .loopHelloWorld
답변2
트랩을 사용하십시오.
#! /bin/bash
trap handleInt SIGINT
interrupted=0
function handleInt {
echo "Interrupted..."
interrupted=1
}
while true
do
[[ interrupted -ne 0 ]] && { echo "Ctrl-C caught, exiting..." ; exit ; }
echo "Sleeping..."
sleep 1
read -r line
echo "$line"
done