Как передать команду bash и сохранить работоспособность Ctrl+C?

Как передать команду bash и сохранить работоспособность Ctrl+C?

Рассматриваем пользовательское программное обеспечение командной строки (например, loopHelloWorld), которое обнаруживает ctrl+C для хорошего завершения работы. Как передать ответ, не теряя Ctrl+C?

$ loopHelloWorld
    - Ctrl+C to nicely shutdown

Но с pipe, pipe убивает программное обеспечение без корректного завершения работы

$ 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сообщение на свой stdout, оно также будет записано в pipe. Если этопослеподоболочка на другом конце уже умерла, тогда 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или ksh93вместо bash. В этих оболочках whileцикл будет выполняться в основном процессе оболочки, поэтому не будет затронут SIGINT.

Это не поможет, 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

Связанный контент