bash 명령을 파이프하고 Ctrl+C를 계속 작동시키는 방법은 무엇입니까?

bash 명령을 파이프하고 Ctrl+C를 계속 작동시키는 방법은 무엇입니까?

원활한 종료를 위해 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에 기록 되면 Ctrl+C to nicely shutdown파이프에도 기록됩니다. 그렇다면뒤쪽에다른 쪽 끝에 있는 서브쉘이 죽었 loopHelloWorld으면반품SIGPIPE가 수신되었으며 이를 처리해야 합니다.

여기서는 명령의 일반적인 출력이 아니기 때문에 stderr에 메시지를 작성해야 합니다(그러나 이 ping예에서는 해당되지 않음). 그러면 파이프를 통과하지 못할 것입니다.

또는 while 루프를 실행하는 서브셸이 SIGINT를 무시하여 loopHelloWorldSIGINT 이후의 출력을 계속 읽도록 할 수 있습니다.

loopHelloWorld | (
  trap '' INT
  while IFS= read -r line; do
    printf '%s\n' "$line"
  done
)

그러나 이로 인해 를 누르면 파이프의 종료 상태가 0이 됩니다 Ctrl+C.

이 특정 예에 대한 또 다른 옵션은 대신 zsh또는 를 사용하는 것입니다 . 이러한 셸에서 루프는 기본 셸 프로세스에서 실행되므로 SIGINT의 영향을 받지 않습니다.ksh93bashwhile

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

관련 정보