Сценарий оболочки возвращает 0 статус выхода _, несмотря на синтаксическую ошибку

Обычно это указывает на то, что ваша программа тратит значительное количество времени на ожидание обработки своего вывода. Ожидание ввода-вывода считается отдельно от использования ЦП. Перенаправляя его вывод на /dev/null, вы устраняете это, и ваша программа тратит больше времени на работу.

10
23.05.2021, 00:22
2 ответа

Позвольте мне сначала объяснить, почему это происходит. Язык команд оболочки POSIX спец говорит:

The exit status of the if command shall be the exit status of the then or else compound-list that was executed, or zero, if none was executed.

Так как в вашем случае thenчасть не выполняется и нет elseстатус выхода равен 0. Он также будет равен 0, если вы запустите этот скрипт, используя Баш как в man bashговорит:

   if list; then list; [ elif list; then list; ]... [ else list; ] fi

          The if list is executed.  If its exit status is zero,
          the then list is executed.  Otherwise, each elif list is
          executed in turn, and if its exit status is zero, the
          corresponding then list is executed and the command
          completes.  Otherwise, the else list is executed, if
          present.  The exit status is the exit sta‐ tus of the
          last command executed, or zero if no condition tested
          true.

How can I detect this kind of error in a script if I can't rely on the exit code?

Я могу придумать два способа:

  • если вы можете изменить свой сценарий, добавьте часть elseв конструкцию if:

      #!/bin/sh
    
      foo=1
      if [[ ! -z $foo ]]; then
          echo abc
      else
          echo not true
          exit 1
      fi
    
  • если вы получили if от кого-то и не хотите его модифицировать, используйте статический анализатор shellcheck в режиме shдля поиска возможных ошибок в код и сообщить о них автору:

      $ shellcheck -s sh dash-exit-status.sh
    
      In dash-exit-status.sh line 4:
      if [[ ! -z $foo ]]; then
         ^-------------^ SC2039: In POSIX sh, [[ ]] is undefined.
            ^-- SC2236: Use -n instead of ! -z.
    
      For more information:
        https://www.shellcheck.net/wiki/SC2039 -- In POSIX sh, [[ ]] is undefined.
        https://www.shellcheck.net/wiki/SC2236 -- Use -n instead of ! -z.
    

По сути, для меня это ошибка , так как не следует использовать не -POSIX функции в сценариях, которые должны выполняться /bin/shкоторый может, но не обязательно должен быть символической ссылкой на Bash.

13
28.07.2021, 11:30

Обратите внимание, что, как прокомментировал @muru, это не синтаксическая ошибка в том, что касается Dash. [не является специальным символом оболочки, в отличие от ;и (. [— это обычная команда вроде echo, только с забавным названием. В Bash/Ksh/Zsh [[является ключевым словом, подобным if, и ключевые слова являются частью синтаксиса оболочки, но, что особенно важно, в оболочках, которые не поддерживают , [[будет обрабатываться как еще одна команда.

Поскольку Dash не поддерживает [[, он ищется в PATHкак любая другая команда, и поиск завершается ошибкой. Как говорится в ответе Аркадиуша Драбчика , результатом здесь является нулевой статус выхода. Если бы это была настоящая синтаксическая ошибка, оболочка немедленно завершила бы работу с ненулевым статусом -.

How can I detect this kind of error in a script if I can't rely on the exit code?

Ну, технически можно...

#!/bin/dash
[[ $1 == "foo" ]]
case $? in
    0)    echo "the first argument was 'foo'";;
    1)    echo "the first argument was something else";;
    127)  echo "[[ not supported";;
    *)    echo "there was some other error";;
esac

Или то же самое с ret=$?и цепочкой из if-elifс условиями против $ret. Это несколько неудобно делать, и не лучшее решение здесь,но если вам действительно нужно различать разные коды ошибок какой-то команды, это то, что вам нужно сделать.

Если вы стремитесь обнаружить, в частности, дело Dash против Bash, вы можете добавить дополнительный тест в начале скрипта, чтобы увидеть, правильно ли работает [[:

#!/bin/bash
if ! [[ a == a ]] 2>/dev/null; then
    echo "[[ not supported, exiting." >&2
    exit 1
fi

#...

Точно так же вы, вероятно, могли бы добавить тесты для всех других не--POSIX-функций, которые вы используете, но их тестирование всех , конечно, может стать немного громоздким.

Чтобы требовать именно Bash, а не любую оболочку с такими же функциями (Ksh и Zsh совместимы с некоторыми вещами, хотя и не со всеми ), проверьте $BASH_VERSIONв начале скрипта:

#!/bin/bash
if [ -z "$BASH_VERSION" ]; then
    echo "Running only with Bash supported, exiting" >&2
    exit 1
fi

#...

(Переменная, конечно, может быть установлена ​​вручную, но чем лучше пользователь будет знать, что он делает.)

5
28.07.2021, 11:30

Теги

Похожие вопросы