Проверка успешности команды в операторе bash 'if [..]'

Я пытаюсь автоматизировать резервное копирование нашего приложения. Частью процесса является проверка состояния выхода egrep в инструкции if:

if [ ! -f /opt/apps/SiteScope_backup/sitescope_configuration.zip ] ||
   [ egrep -i -q "error|warning|fatal|missing|critical" "$File" ]
then 
  echo "testing"
fi

Я ожидал, что он выдаст testing, потому что файл существует и egrep вернет успех, но вместо этого я получаю ошибку:

-bash: [: too many arguments

Я пытался использовать любой синтаксис - дополнительные скобки, кавычки и т.д., но ошибка все еще сохраняется.

Пожалуйста, помогите мне понять, где я иду не так.

Ответ 1

Вы делаете общую ошибку, считая, что [ является частью синтаксиса оператора if. Это не; синтаксис if - это просто

if command; then
    ... things which should happen if command result code was 0
else
    ... things which should happen otherwise
fi

Один из распространенных command, которые мы используем, это [, который является псевдонимом для команды test. Это простая команда для сравнения строк, чисел и файлов. Он принимает довольно узкую комбинацию аргументов и, как правило, создает путаные и вводящие в заблуждение сообщения об ошибках, если вы не передадите ему ожидаемые аргументы. (Вернее, сообщения об ошибках являются адекватными и полезными, когда вы привыкаете к нему, но их легко понять, если вы не используете.)

Здесь вы хотите проверить результат команды egrep:

if [ ! -f /opt/apps/SiteScope_backup/sitescope_configuration.zip ] ||
   egrep -i -q "error|warning|fatal|missing|critical" "$File"
then
    echo "testing"
fi

В общем случае command может быть конвейером или списком команд; то код завершения из последней команды - это состояние, которое будет проверять if, подобно тому, как последняя команда в script определяет статус выхода из script.

Эти составные команды могут быть сколь угодно сложными, например

if read thing
    case $thing in
      '' | 'quit') false;;
      *) true;;
    esac
then ...

но на практике вы редко видите больше одной команды в операторе if (хотя это не является неслыханным, ваш составной оператор с || является хорошим примером!)

Исторические причины test как общей кухонной раковины, которую авторы не хотели делать частью синтаксиса if, являются одним из менее привлекательных дизайнов оригинальной оболочки Bourne. Bash и zsh предлагают альтернативы, которые являются менее громоздкими (например, двойные скобки [[ в bash), и, конечно же, POSIX test является намного более вспыльчивым, чем оригинальное создание Bell Labs.

Ответ 2

Это работает: поместите ваш egrep в "$()", удалите -q и сравните строку:

if [ ! -f /opt/apps/SiteScope_backup/sitescope_configuration.zip ] ||
   [ "$(egrep -i 'error|warning|fatal|missing|critical' $File)" != "" ];
then

   echo "testing";

fi