Bash: как прервать этот скрипт, когда есть CTRL-C?

Я написал крошечный скрипт Bash, чтобы найти все наборы изменений Mercurial (начиная с подсказки), которые содержат строку, переданную в аргументе:

#!/bin/bash

CNT=$(hg tip | awk '{ print $2 }' | head -c 3)
while [ $CNT -gt 0 ]
do
    echo rev $CNT
    hg log -v -r$CNT | grep $1       
    let CNT=CNT-1
done

Если я прерываю его, нажимая ctrl-c, чаще всего в данный момент выполняется команда «hg log», и именно эта команда прерывается, но затем мой сценарий продолжается.

Затем я подумал о проверке статуса возврата "hg log", но поскольку я передаю его в grep, я не слишком уверен, как это сделать...

Как мне выйти из этого сценария, когда он прерван? (кстати, я не знаю, хорош ли этот скрипт вообще для того, что я хочу сделать, но он выполняет свою работу, и в любом случае меня интересует проблема «прерванного»)


person SyntaxT3rr0r    schedule 31.03.2010    source источник


Ответы (3)


Перепишите свой скрипт следующим образом, используя массив $PIPESTATUS для проверки наличия ошибок:

#!/bin/bash

CNT=$(hg tip | awk '{ print $2 }' | head -c 3)
while [ $CNT -gt 0 ]
do
    echo rev $CNT
    hg log -v -r$CNT | grep $1
    if [ 0 -ne ${PIPESTATUS[0]} ] ; then
            echo hg failed
            exit
    fi     
    let CNT=CNT-1
done
person Dan Story    schedule 31.03.2010
comment
Я, вероятно, должен указать, что и $PIPESTATUS, и опция pipefail, о которой упоминал Аркку, специфичны для Bash версии 3+. Они не поддерживаются другими оболочками. - person Dan Story; 31.03.2010
comment
спасибо, на моих Debian Linux у меня действительно есть Bash 3+, но на моих Mac это Bash 2.05. - person SyntaxT3rr0r; 31.03.2010
comment
Действительно? Это удивительно. Я использую bash 3.2.48 на своем MacBook Pro и не помню, чтобы сам обновлял его. Какую версию OS X вы используете? - person Dan Story; 31.03.2010
comment
Leopard на моем MacBook Pro, у которого сегодня утром произошел сбой жесткого диска, поэтому проверить не могу ;) И 10.4.11 на моем Mac Minis (это те, которые имеют Bash 2.05), которые мне нужно специально протестировать, потому что мы доставка приложений на 10.4, 10.5 и 10.6, поэтому нам нужны эти старые версии OS X для тестирования нашего программного обеспечения. - person SyntaxT3rr0r; 31.03.2010

Поместите в начало вашего скрипта: trap 'echo interrupted; exit' INT

Редактировать: Как отмечено в комментариях ниже, вероятно, это не работает для программы OP из-за канала. Решение $PIPESTATUS работает, но может быть проще настроить сценарий на выход, если какая-либо программа в канале завершается со статусом ошибки: set -e -o pipefail

person Arkku    schedule 31.03.2010
comment
Команда trap работает только с процессами, которые сами не перехватывают прерывания. Если бы сценарий получал прерывание, он бы уже прервал себя. - person Dan Story; 31.03.2010
comment
Ах, извините, я пропустил трубку в сценарии ОП. Лучшим ответом может быть: set -e pipefail - person Arkku; 31.03.2010
comment
Ваше первое решение (ловушка) будет работать с любым процессом, который сам не перехватывает прерывания — find является хорошим примером долго выполняющегося процесса, который проходит через прерывание, заставляя сценарий прервать. Ловушка может использоваться для предотвращения немедленного прерывания сценария для выполнения очистки, вроде деструктора или финализатора. Это удобная команда, о которой нужно знать. - person Dan Story; 31.03.2010
comment
Это должно быть set -o pipefail. - person Dennis Williamson; 31.03.2010
comment
На самом деле, я имел в виду set -e -o pipefail, -e, чтобы заставить скрипт программы завершиться при ошибке, и -o pipefail, чтобы заставить канал выйти из строя, если hg возвращает статус ошибки. - person Arkku; 31.03.2010
comment
Однако вы можете не захотеть, чтобы скрипт завершал работу при других ошибках. - person musiphil; 01.12.2012
comment
@musiphil Если вы не хотите, чтобы скрипт завершал работу при других ошибках, просто поместите set -e -o pipefail непосредственно перед каналом, который вы хотите использовать, а затем отключите эти параметры, используя set +e +o pipefail после канала, к которому вы хотите его применить. - person Cory Gross; 18.09.2020

Переменная $PIPESTATUS позволит вам проверить результаты каждого члена канала.

person Ignacio Vazquez-Abrams    schedule 31.03.2010