Получить код выхода для команды в bash/ksh
Я хочу написать такой код:
command="some command"
safeRunCommand $command
safeRunCommand() {
cmnd=$1
$($cmnd)
if [ $? != 0 ]; then
printf "Error when executing command: '$command'"
exit $ERROR_CODE
fi
}
Но этот код работает не так, как я хочу.
Где я ошибся?
Ответы
Ответ 1
Ниже приведен фиксированный код:
#!/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 else 1.
Я тестировал с KSH/ BASH. И все получилось отлично. Дайте мне знать, если у вас возникли проблемы с этим.
Ответ 2
Try
safeRunCommand() {
"[email protected]"
if [ $? != 0 ]; then
printf "Error when executing command: '$1'"
exit $ERROR_CODE
fi
}
Ответ 3
Он должен быть $cmd
вместо $($cmd)
. Хорошо работает с этим на моей коробке.
Изменить: Ваш script работает только для команд с одним словом, например ls. Это не будет работать для "ls cpp". Для этого замените cmd="$1"; $cmd
на "[email protected]"
. И не запускайте script как command="some cmd"; safeRun command
, запустите его как safeRun some cmd
.
Кроме того, когда вам нужно отлаживать ваши сценарии bash, выполните с помощью флага -x. [bash -x s.sh].
Ответ 4
В вашем script есть несколько ошибок.
Функции (подпрограммы) должны быть объявлены перед попыткой вызвать их. Вероятно, вы хотите возвратить(), но не выйти() из своей подпрограммы, чтобы позволить вызывающему блоку проверить успех или сбой конкретной команды. В остальном вы не захватываете "ERROR_CODE", поэтому всегда ноль (undefined).
Хорошая практика - объединить ваши переменные ссылки с фигурными фигурными скобками. Ваш код может выглядеть так:
#!/bin/sh
command="/bin/date -u" #...Example Only
safeRunCommand() {
cmnd="[email protected]" #...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
Ответ 5
Обычной идеей было бы запустить команду, а затем использовать $?
для получения кода выхода. Однако несколько раз у вас есть несколько случаев, когда вам нужно получить код выхода. Например, вам может потребоваться скрыть его вывод, но все же вернуть код выхода или распечатать код выхода и выход.
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
.