How to check if a command succeeded?
Prefer $(foo) over backticks `foo`, because you can nest it, and it’s easier to distinguish from apostrophes.
10 Answers 10
The return value is stored in $? . 0 indicates success, others indicates error.
some_command if [ $? -eq 0 ]; then echo OK else echo FAIL fi
Like any other textual value, you can store it in a variable for future comparison:
some_command retval=$? do_something $retval if [ $retval -ne 0 ]; then echo "Return code was not zero but $retval" fi
For possible comparison operators, see man test .
That’s nice . can i hold the output error . , because in this case i have 2 error : command error «text» ex, file not found and my error «text» Which is in this case failed for example
@Blauhirn [ $? ] (or equivalently, test $? ) does not work because $? evaluates to a number (0, 1, etc.) which is not null. See the docs for test : «If EXPRESSION is omitted, ‘test’ returns false. If EXPRESSION is a single argument, ‘test’ returns false if the argument is null and true otherwise.»
If you only need to know if the command succeeded or failed, don’t bother testing $? , just test the command directly. E.g.:
if some_command; then printf 'some_command succeeded\n' else printf 'some_command failed\n' fi
And assigning the output to a variable doesn’t change the return value (well, unless it behaves differently when stdout isn’t a terminal of course).
if output=$(some_command); then printf 'some_command succeded, the output was «%s»\n' "$output" fi
What if you want to do something other than branching like storing the boolean of whether it failed or not into a .ini? Then your output variable doesn’t do that, but $? does, so you’re incorrect in saying that testing the command directly is strictly better.
Assigning the output to a variable may change the return value when one uses local command, i.e. local foo=$(false); echo $?; produces 0 on the output. But local is only relevant inside of bash functions.
@Prometheus hard to say without seeing the code. Perhaps it incorrectly returns 0 in the case you considered a failure, or perhaps you added additional commands to the command substitution without using && between them.
I’m not used to bash scripting. Does the if require some brackets or anything? Can I just have. if cd unreliable_dir; then
command && echo OK || echo Failed
If command writes errors out to stderr, you can use the form command 2> /dev/null && echo OK || echo Failed . The 2> /dev/null redirects stderr output to /dev/null . However, some utilities will write errors to stdout (even though this is bad practice). In this case you can omit the 2 from the redirection, but you will lose any output from the command. This method of checking success is good for simple ternary logic but for more complex behavior it’s best to check $? for command success, or use the if block method outlined in @geirha’s answer.
$? should contain the exit status of the previous command, which should be zero for no error.
cd /nonexistant if [ $? -ne 0 ] then echo failed else echo success! fi
for most cases, it’s easier to use the && construct to chain commands that need to depend on each other. So cd /nonexistant && echo success! would not echo success because the command breaks before && . The corollary of this is || , where cd /nonexistant || echo fail would echo fail because cd failed (this becomes useful if you use something like ||exit , which will end the script if the previous command failed).
That’s nice . can i hold the output error . , because in this case i have 2 error : command error «text» ex, file not found and my error «text» Which is in this case failed for example
No, my line is correct, it gives the actual result code as a number regardless if success or failure.
Ok, please explain the differences of these to me: true && echo $? || echo $? / true; echo $? and false && echo $? || echo $? / false; echo $? — you’ll find, they do the exact same thing 😀
Yes, the same result but without the condition. The original question asked was «How to check if a command succeeded?», this was based on previous answers. I guess a better example would be: command && echo «success: $?» || echo «fail: $?»
It should be noted that if. then. fi and && / || type of approach deals with exit status returned by command we want to test( 0 on success ); however, some commands don’t return a non-zero exit status if command failed or couldn’t deal with input. This means that the usual if and && / || approaches won’t work for those particular commands.
For instance, on Linux GNU file still exits with 0 if it received a non-existing file as argument and find couldn’t locate the file user specified.
$ find . -name "not_existing_file" $ echo $? 0 $ file ./not_existing_file ./not_existing_file: cannot open `./not_existing_file' (No such file or directory) $ echo $? 0
In such cases, one potential way we could handle the situation is by reading stderr / stdin messages, e.g. those that returned by file command, or parse output of the command like in find . For that purposes, case statement could be used.
$ file ./doesntexist | while IFS= read -r output; do > case "$output" in > *"No such file or directory"*) printf "%s\n" "This will show up if failed";; > *) printf "%s\n" "This will show up if succeeded" ;; > esac > done This will show up if failed $ find . -name "doesn'texist" | if ! read IFS= out; then echo "File not found"; fi File not found
Проверить выполнение скрипта
Вопрос: как лучше проверить, выполняется ли команда в rc.local при загрузке?
Может какие-то if нужны туда еще + в лог отправлять выхлоп.
Подскажите, пожалуйста, кто делал такое и как.
Собственно, у меня там всего лишь синхронизация времени, но на будущее хотелось бы знать, если что:
sleep 60 ntpdate -s & exit 0
А разве это будет сильно отличаться в других? 🙂
( echo "Executing" sleep 60 nohup ntpdate -s > /tmp/debug & ) &
screen -d -m bash -c "sleep 60; ntpdate -s"
screen -d -m bash -c «sleep 60; ntpdate -s»
Никогда не юзал screen, что даст эта команда? Где будет выхлоп или лог?
«screen -r» и ты подключишься к псевдотерминалу с выхлопом.
Вопрос: как лучше проверить, выполняется ли команда в rc.local при загрузке?
ну если скрипт самописный, то лучший, наверное, способ — это создание файлов-маркеров. У камрада цельные системы собирались через использование таких маркеров. Довольно большие системы, на десятки виртуалок.
Я ща точно не помню какой там в баше знак (кажется &&)
targitaj ★★★★★ ( 30.03.16 19:17:52 MSK )
Последнее исправление: targitaj 30.03.16 19:20:06 MSK (всего исправлений: 1)
Да там не скрипт, а в rc.local:
sleep 60 ntpdate -s & exit 0
Все намного проще. Хотел вот узнать, как мониторить выполнение той или иной команды на предмет ее успешного выполнения.
Ок, спасибо, разбираюсь. Полезная штука.
то это и есть скрипт )))) Просто он написан не тобой.
#!/bin/sh -e # # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing. exit 0
это обычный скрипт, на него действуют все обычные правила. Одним скриптом ты создаёшь маркеры по факту успешного выполнения или фейла, а другим скриптом проверяешь эти маркеры. Через крон, например. Ну или руками. Главное — не забывать удалять файл-маркер после проверки. Или, как вариант, удалять файл-маркер перед выполнением критичной части скрипта.
Вопрос: как лучше проверить, выполняется ли команда в rc.local при загрузке?
Выполняется, будь уверен. Проверку добавляй до exit 0
1. Если ты пытаешься что-то добавить в скрипты инициализации, будь уверен что указываешь полные пути, или убедись что установил PATH
2. В debian в качестве «sh» по умолчанию dash вместо bash. Это многих смущает
Скорее всего выполнено не будет, из-за отсутствия полных путей
Кроме того, не уверен, но сильно подозреваю, что () работает в bash, но не голом sh. Если так, то не пройдёт.
🐧 Как отлажидить / проверить скрипты Bash
Некоторые основные инструменты, такие как использование редактора с подсветкой синтаксиса, также помогут.
Есть встроенные опции, которые Bash сам по себе предоставляет, чтобы упростить отладку и ежедневную работу системного администратора Linux.
- Как использовать традиционные методы
- Как использовать параметр xtrace
- Как использовать другие параметры Bash
- Как использовать trap
Используя Традиционные Методы
Отладка кода может быть сложной, даже если ошибки просты и очевидны.
Для помощи программистам традиционно использовались такие инструменты, как отладчики и подсветка синтаксиса в редакторах.
Ничего не меняется при написании скриптов Bash.
Простое выделение синтаксиса позволит вам отлавливать ошибки при написании кода, избавляя вас от трудоемкой задачи отслеживания ошибок на более позднем этапе.
Некоторые языки программирования поставляются с сопутствующими средами отладки, такими как gcc и gdb, которые позволяют вам шагать по коду, устанавливать точки останова, исследовать состояние всего в моменты выполнения и многое другое – но, как правило, тут не требуется такой сложный подход, как этот с скрипт оболочки и код просто интерпретируется, а не компилируется в двоичные файлы.
Существуют методы, используемые в традиционных средах программирования, которые могут быть полезны со сложными скриптами Bash, например, с использованием утверждений.
В основном это способы явного утверждения условий или состояния вещей в определенный момент времени.
Утверждения могут выявить даже самые незначительные ошибки.
Они могут быть реализованы в виде короткой функции, которая показывает время, номер строки и тому подобное, или что-то вроде этого:
$ echo "function_name(): value of \$var is $"
Как использовать опцию Bash xtrace
При написании скриптов оболочки логика программирования имеет тенденцию быть короче и часто содержится в одном файле.
Таким образом, есть несколько встроенных опций отладки, которые мы можем использовать, чтобы увидеть, что происходит не так.
Первый вариант, который стоит упомянуть, вероятно, самый полезный – параметр xtrace.
Его можно применить к скрипту, вызвав Bash с ключом -x.
Он говорит Bash показать нам, как выглядит каждое выражение непосредственно перед тем, как оно выполнится.
Вскоре мы увидим пример этого параметра в действии, но сначала давайте начнем с контраста -x с его противоположностью -v, который показывает каждую строку до ее оценки, а не после.
Опции можно комбинировать, и, используя -x и -v, вы можете увидеть, как выглядят операторы до и после замены переменных.
Как использовать другие параметры Bash
Параметры отладки Bash по умолчанию отключены, но как только они включаются с помощью команды set, они остаются включенными до тех пор, пока не будут явно отключены.
Если вы не уверены, какие опции включены, вы можете проверить переменную $ -, чтобы увидеть текущее состояние всех переменных.
$ echo $- himBHs $ set -xv && echo $- himvxBHs
Есть еще один полезный ключ, который мы можем использовать, чтобы помочь нам найти переменные, на которые что-то ссылается, без установки какого-либо значения.
Мы можем использовать эти опции в коротких скриптах Bash, чтобы предоставить нам информацию отладки для выявления проблем, которые иначе не вызовут обратную связь от интерпретатора Bash.
Как использовать trap, чтобы помочь в отладке
Есть более сложные методы, которые стоит рассмотреть, если ваши скрипты большиие сложные, включая использование функции assert, как упоминалось ранее.
Один из таких методов, о которых следует помнить, – это использование trap bash позволяют нам перехватывать сигналы и что-то делать в этой точке.
Простой, но полезный пример, который вы можете использовать в своих скриптах Bash – это trap EXIT.
Заключение
Если вы заметили, что ваш скрипт Bash ведет себя не так, как ожидалось, и причина по какой-либо причине вам не ясна, подумайте, какая информация будет полезна, чтобы помочь вам определить причину, а затем используйте наиболее удобные инструменты, доступные для определения проблем.
Опция xtrace -x проста в использовании и, вероятно, является наиболее полезной из представленных здесь опций, поэтому попробуйте попробовать ее в следующий раз, когда вы столкнетесь со скриптом, который не выполняет то, что, по вашему мнению должно произойти.