Получить код выхода для команды в bash / ksh - PullRequest
50 голосов
/ 21 ноября 2011

Я хочу написать такой код:

command="some command"

safeRunCommand $command

safeRunCommand() {
   cmnd=$1

   $($cmnd)

   if [ $? != 0 ]; then
      printf "Error when executing command: '$command'"
      exit $ERROR_CODE
   fi
}

Но этот код работает не так, как я хочу.Где я ошибся?

Ответы [ 5 ]

64 голосов
/ 22 ноября 2011

Ниже приведен фиксированный код:

#!/bin/ksh
safeRunCommand() {
  typeset cmnd="$*"
  typeset ret_code

  echo cmnd=$cmnd
  eval $cmnd
  ret_code=$?
  if [ $ret_code != 0 ]; then
    printf "Error : [%d] when executing command: '$cmnd'" $ret_code
    exit $ret_code
  fi
}

command="ls -l | grep p"
safeRunCommand "$command"

Теперь, если вы посмотрите на этот код, я изменил несколько вещей:

  • использование typeset не обязательно, нохорошая практика.Это делает cmnd и ret_code локальными для safeRunCommand
  • использование ret_code не является необходимым, но является хорошей практикой для хранения кода возврата в некоторой переменной (и сохранения его как можно скорее), чтобы вы могли использоватьпозже, как я сделал в printf "Error : [%d] when executing command: '$command'" $ret_code
  • , передал команду с кавычками, окружающими команду, например safeRunCommand "$command".Если вы этого не сделаете, cmnd получит только значение ls, а не ls -l.И еще более важно, если ваша команда содержит каналы.
  • вы можете использовать typeset cmnd="$*" вместо typeset cmnd="$1", если хотите сохранить пробелы.Вы можете попробовать оба варианта, в зависимости от того, насколько сложен ваш аргумент команды.
  • eval используется для оценки, чтобы команда, содержащая каналы, могла нормально работать

ПРИМЕЧАНИЕ. Помните, что некоторые команды дают 1в качестве кода возврата, даже если нет ошибки, такой как grep.Если grep что-то найдет, он вернет 0, иначе 1.

Я тестировал с KSH / BASH.И это работало нормально.Дайте мне знать, если у вас возникнут проблемы с этим.

5 голосов
/ 21 ноября 2011

Попробуйте

safeRunCommand() {
   "$@"

   if [ $? != 0 ]; then
      printf "Error when executing command: '$1'"
      exit $ERROR_CODE
   fi
}
2 голосов
/ 21 ноября 2011

Должно быть $cmd вместо $($cmd).Хорошо работает с этим на моем компьютере.

Редактировать: Ваш скрипт работает только для команд из одного слова, таких как ls.Это не будет работать для "ls cpp".Чтобы это работало, замените cmd="$1"; $cmd на "$@".И не запускайте ваш скрипт как command="some cmd"; safeRun command, запустите его как safeRun some cmd.

Кроме того, когда вам нужно отладить ваши bash-скрипты, выполняйте с флагом '-x'.[bash -x s.sh].

1 голос
/ 21 ноября 2011

В вашем скрипте есть несколько ошибок.

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

Хорошей практикой также является окружение ссылок на переменные фигурными скобками. Ваш код может выглядеть так:

#!/bin/sh
command="/bin/date -u"          #...Example Only

safeRunCommand() {
   cmnd="$@"                    #...insure whitespace passed and preserved
   $cmnd
   ERROR_CODE=$?                #...so we have it for the command we want
   if [ ${ERROR_CODE} != 0 ]; then
      printf "Error when executing command: '${command}'\n"
      exit ${ERROR_CODE}        #...consider 'return()' here
   fi
}

safeRunCommand $command
command="cp"
safeRunCommand $command
0 голосов
/ 11 сентября 2017

Обычной идеей было бы запустить команду и затем использовать $? для получения кода выхода.Однако иногда у вас есть несколько случаев, когда вам нужно получить код выхода.Например, вам может потребоваться скрыть его вывод, но все равно вернуть код выхода или вывести как код выхода, так и вывод.

ec() { [[ "$1" == "-h" ]] && { shift && eval $* > /dev/null 2>&1; ec=$?; echo $ec; } || eval $*; ec=$?; }

Это даст вам возможность подавить вывод команды, для которой вы хотите код выхода.Когда вывод для команды подавлен, код выхода будет напрямую возвращен функцией.

Мне лично нравится помещать эту функцию в мой .bashrc файл

Ниже я продемонстрирую несколькоспособы, которыми вы можете использовать это:


# In this example, the output for the command will be
# normally displayed, and the exit code will be stored
# in the variable $ec.

$ ec echo test
test
$ echo $ec
0

# In this example, the exit code is output
# and the output of the command passed
# to the `ec` function is suppressed.

$ echo "Exit Code: $(ec -h echo test)"
Exit Code: 0

# In this example, the output of the command
# passed to the `ec` function is suppressed
# and the exit code is stored in `$ec`

$ ec -h echo test
$ echo $ec
0

Решение вашего кода с помощью этой функции

#!/bin/bash
if [[ "$(ec -h 'ls -l | grep p')" != "0" ]]; then
    echo "Error when executing command: 'grep p' [$ec]"
    exit $ec;
fi

Следует также отметить, что код выхода, который вы увидите, будет для команды grep, которая выполняется, поскольку это последняя выполняемая команда.Не ls.

...