Почему set -e вызывает мой скрипт для завершения, когда он встречает следующее? - PullRequest
2 голосов
/ 07 января 2010

У меня есть скрипт bash, который проверяет некоторые файлы журнала, созданные заданием cron, которые имеют временные метки в имени файла (с точностью до секунды). Используется следующий код:

CRON_LOG=$(ls -1 $LOGS_DIR/fetch_cron_{true,false}_$CRON_DATE*.log 2> /dev/null | sed 's/^[^0-9][^0-9]*\([0-9][0-9]*\).*/\1 &/' | sort -n | cut -d ' ' -f2- | tail -1 )
if [ -f "$CRON_LOG" ]; then
    printf "Checking $CRON_LOG for errors\n"
else
        printf "\n${txtred}Error: cron log for $CRON_NOW does not exist.${txtrst}\n"
        printf "Either the specified date is too old for the log to still be around or there is a problem.\n"
        exit 1
fi
CRIT_ERRS=$(cat $CRON_LOG | grep "ERROR" | grep -v "Duplicate tracking code")
if [ -z "$CRIT_ERRS" ]; then
        printf "%74s[${txtgrn}PASS${txtrst}]\n"
else
        printf "%74s[${txtred}FAIL${txtrst}]\n"
        printf "Critical errors detected! Outputting to console...\n"
        echo $CRIT_ERRS
fi

Так что этот фрагмент кода работает нормально, но сейчас я пытаюсь очистить свои скрипты и реализовать set -e на вершине всех из них. Когда я делаю это с этим сценарием, он завершается с кодом ошибки 1. Обратите внимание, что у меня есть ошибки из первого оператора, сбрасывающего в / dev / null. Это связано с тем, что в некоторые дни в файле есть слово «true», а в другие - «false». Во всяком случае, я не думаю, что это моя проблема, потому что скрипт выводит «Проверка xxxxx.log на наличие ошибок». перед выходом, когда я добавляю set -e к вершине.

Примечание: переменная $ CRON_DATE является производной от пользовательского ввода. Я могу выполнить точно такой же оператор из командной строки "$. / Checkcron.sh 01/06/2010", и он отлично работает без оператора set -e в верхней части скрипта.

ОБНОВЛЕНИЕ: я добавил "set -x" в свой скрипт и сузил проблему. Последний бит вывода:

Checking /map/etl/tektronix/logs/fetch_cron_false_010710054501.log for errors
++ cat /map/etl/tektronix/logs/fetch_cron_false_010710054501.log
++ grep ERROR
++ grep -v 'Duplicate tracking code'
+ CRIT_ERRS=

[1]+  Exit 1                  ./checkLoad.sh...

Похоже, проблема возникает в этой строке:

CRIT_ERRS=$(cat $CRON_LOG | grep "ERROR" | grep -v "Duplicate tracking code")

Любая помощь приветствуется. :)

Спасибо, Райан

Ответы [ 4 ]

3 голосов
/ 07 января 2010

Добавление set -x, которое печатает след выполнения скрипта, может помочь вам диагностировать источник ошибки.

Редактировать:

Ваш grepвозвращает код завершения 1, поскольку он не находит строку «ОШИБКА».

Редактировать 2:

Мои извинения за двоеточие.Я не проверял это.

Тем не менее, следующие работы (я проверил это перед тем, как изливаться) и избегают вызова внешнего cat.Поскольку вы устанавливаете переменную, используя результаты подоболочки, а set -e смотрит на подоболочку в целом, вы можете сделать это:

CRIT_ERRS=$(cat $CRON_LOG | grep "ERROR" | grep -v "Duplicate tracking code"; true)
2 голосов
/ 07 января 2010
bash -c 'f=`false`; echo $?'
1
bash -c 'f=`true`; echo $?'
0
bash -e -c 'f=`false`; echo $?'
bash -e -c 'f=`true`; echo $?'
0

Обратите внимание, что обратные галочки (и $()) "возвращают" код ошибки последней команды, которую они запускают. Решение:

CRIT_ERRS=$(cat $CRON_LOG | grep "ERROR" | grep -v "Duplicate tracking code" | cat)
2 голосов
/ 07 января 2010

Запрос set -e заставляет скрипт завершиться, как только выходит простая команда с ненулевым статусом выхода. Это пагубно сочетается с вашей командой ls, которая выходит с ненулевым статусом при запросе списка несуществующего файла, что всегда так, потому что варианты true и false не совместимы есть.

1 голос
/ 07 января 2010

Ошибка перенаправления сообщения на /dev/null ничего не делает с статусом выхода , возвращаемым сценарием. Причина, по которой ваша команда ls не вызывает ошибку, заключается в том, что она является частью конвейера, а состояние выхода конвейера - это возвращаемое в ней значение last (если только pipefail не является включен).

Учитывая ваше обновление, похоже, что команда, которая терпит неудачу, является последней grep в конвейере. grep возвращает 0 только если находит совпадение; в противном случае он возвращает 1, а в случае ошибки - 2. Это опасность set -e; вещи могут потерпеть неудачу, даже если вы этого не ожидаете, потому что такие команды, как grep, возвращают ненулевой статус, даже если не было ошибки. Он также не может завершиться с ошибками ранее в конвейере и может пропустить некоторую ошибку.

Решения, предоставленные geocar или ephemient (передача по cat или использование || : для гарантии успешного возврата последней команды в трубе), должны помочь вам обойти это, если вы действительно хотите использовать set -e.

...