- How to get exit code and stdout of a linux command at the same time
- 3 Answers 3
- Как использовать коды завершения в Bash-скриптах
- Что такое коды завершения
- Что происходит, когда коды завершения не определены
- Как использовать коды завершения в Bash-скриптах
- Проверяем коды завершения
- Создаём собственный код завершения
- Как использовать коды завершения в командной строке
- Дополнительные коды завершения
- Linux and Unix exit code tutorial with examples
- What is an exit code in the UNIX or Linux shell? ¶
- How to get the exit code of a command ¶
- How to use exit codes in scripts ¶
- How to set an exit code ¶
- What exit code should I use? ¶
- How to suppress exit statuses ¶
- Further reading ¶
- Tags
- See Also
How to get exit code and stdout of a linux command at the same time
I execute a curl [url] command in a Linux shell script. I want to get this command’s exit code and its output at the same time without using a temporary file. Is there any method to do that?
I left an answer that fulfills your criteria of output and exit code without a temp file. Please edit your question with more details if you had something more specific in mind.
3 Answers 3
I’m assuming the problem is that you have an intermediary command that’s supplanting the exit code of the last command.
To get around this, just store the exit code and stdout in variables:
OUTPUT=$(curl example.org) EXIT_CODE=$?
then you can simply output these either in the same line:
or call them separately as needed.
(I don’t have enough reputation points to comment on user559633’s answer.)
Apparently this won’t work if you send STDOUT to a local variable:
#!/bin/bash function test1 () < OUTPUT=$( ping -c 1 -W 1 blah.org ) EXIT_CODE=$? echo "$EXIT_CODE: $OUTPUT" >function test2 () < local OUTPUT=$( ping -c 1 -W 1 blah.org ) EXIT_CODE=$? echo "$EXIT_CODE: $OUTPUT" >test1 test2
# ./test.sh 1: PING blah.org (205.150.150.140) 56(84) bytes of data. --- blah.org ping statistics --- 1 packets transmitted, 0 received, 100% packet loss, time 0ms 0: PING blah.org (205.150.150.140) 56(84) bytes of data. --- blah.org ping statistics --- 1 packets transmitted, 0 received, 100% packet loss, time 0ms
Note the exitcode from test1 is 1, but for test2, it’s 0.
EDIT: It seems that separating the local declaration from the assignment takes care of this:
#!/bin/bash function test1 () < OUTPUT=$( ping -c 1 -W 1 blah.org ) EXIT_CODE=$? echo "$EXIT_CODE: $OUTPUT" >function test2 () < local OUTPUT OUTPUT=$( ping -c 1 -W 1 blah.org ) EXIT_CODE=$? echo "$EXIT_CODE: $OUTPUT" >test1 test2
1: PING blah.org (205.150.150.140) 56(84) bytes of data. --- blah.org ping statistics --- 1 packets transmitted, 0 received, 100% packet loss, time 0ms 1: PING blah.org (205.150.150.140) 56(84) bytes of data. --- blah.org ping statistics --- 1 packets transmitted, 0 received, 100% packet loss, time 0ms
Как использовать коды завершения в Bash-скриптах
Инструменты автоматизации и мониторинга удобны тем, что разработчик может взять готовые скрипты, при необходимости адаптировать и использовать в своём проекте. Можно заметить, что в некоторых скриптах используются коды завершения (exit codes), а в других нет. О коде завершения легко забыть, но это очень полезный инструмент. Особенно важно использовать его в скриптах командной строки.
Что такое коды завершения
В Linux и других Unix-подобных операционных системах программы во время завершения могут передавать значение родительскому процессу. Это значение называется кодом завершения или состоянием завершения. В POSIX по соглашению действует стандарт: программа передаёт 0 при успешном исполнении и 1 или большее число при неудачном исполнении.
Почему это важно? Если смотреть на коды завершения в контексте скриптов для командной строки, ответ очевиден. Любой полезный Bash-скрипт неизбежно будет использоваться в других скриптах или его обернут в однострочник Bash. Это особенно актуально при использовании инструментов автоматизации типа SaltStack или инструментов мониторинга типа Nagios. Эти программы исполняют скрипт и проверяют статус завершения, чтобы определить, было ли исполнение успешным.
Кроме того, даже если вы не определяете коды завершения, они всё равно есть в ваших скриптах. Но без корректного определения кодов выхода можно столкнуться с проблемами: ложными сообщениями об успешном исполнении, которые могут повлиять на работу скрипта.
Что происходит, когда коды завершения не определены
В Linux любой код, запущенный в командной строке, имеет код завершения. Если код завершения не определён, Bash-скрипты используют код выхода последней запущенной команды. Чтобы лучше понять суть, обратите внимание на пример.
#!/bin/bash touch /root/test echo created file
Этот скрипт запускает команды touch и echo . Если запустить этот скрипт без прав суперпользователя, команда touch не выполнится. В этот момент мы хотели бы получить информацию об ошибке с помощью соответствующего кода завершения. Чтобы проверить код выхода, достаточно ввести в командную строку специальную переменную $? . Она печатает код возврата последней запущенной команды.
Как видно, после запуска команды ./tmp.sh получаем код завершения 0 . Этот код говорит об успешном выполнении команды, хотя на самом деле команда не выполнилась. Скрипт из примера выше исполняет две команды: touch и echo . Поскольку код завершения не определён, получаем код выхода последней запущенной команды. Это команда echo , которая успешно выполнилась.
Если убрать из скрипта команду echo , можно получить код завершения команды touch .
Поскольку touch в данном случае — последняя запущенная команда, и она не выполнилась, получаем код возврата 1 .
Как использовать коды завершения в Bash-скриптах
Удаление из скрипта команды echo позволило нам получить код завершения. Что делать, если нужно сделать разные действия в случае успешного и неуспешного выполнения команды touch ? Речь идёт о печати stdout в случае успеха и stderr в случае неуспеха.
Проверяем коды завершения
Выше мы пользовались специальной переменной $? , чтобы получить код завершения скрипта. Также с помощью этой переменной можно проверить, выполнилась ли команда touch успешно.
#!/bin/bash touch /root/test 2> /dev/null if [ $? -eq 0 ] then echo "Successfully created file" else echo "Could not create file" >&2 fi
После рефакторинга скрипта получаем такое поведение:
- Если команда touch выполняется с кодом 0 , скрипт с помощью echo сообщает об успешно созданном файле.
- Если команда touch выполняется с другим кодом, скрипт сообщает, что не смог создать файл.
Любой код завершения кроме 0 значит неудачную попытку создать файл. Скрипт с помощью echo отправляет сообщение о неудаче в stderr .
Создаём собственный код завершения
Наш скрипт уже сообщает об ошибке, если команда touch выполняется с ошибкой. Но в случае успешного выполнения команды мы всё также получаем код 0 .
Поскольку скрипт завершился с ошибкой, было бы не очень хорошей идеей передавать код успешного завершения в другую программу, которая использует этот скрипт. Чтобы добавить собственный код завершения, можно воспользоваться командой exit .
#!/bin/bash touch /root/test 2> /dev/null if [ $? -eq 0 ] then echo "Successfully created file" exit 0 else echo "Could not create file" >&2 exit 1 fi
Теперь в случае успешного выполнения команды touch скрипт с помощью echo сообщает об успехе и завершается с кодом 0 . В противном случае скрипт печатает сообщение об ошибке при попытке создать файл и завершается с кодом 1 .
Как использовать коды завершения в командной строке
Скрипт уже умеет сообщать пользователям и программам об успешном или неуспешном выполнении. Теперь его можно использовать с другими инструментами администрирования или однострочниками командной строки.
В примере выше && используется для обозначения «и», а || для обозначения «или». В данном случае команда выполняет скрипт ./tmp.sh , а затем выполняет echo «bam» , если код завершения 0 . Если код завершения 1 , выполняется следующая команда в круглых скобках. Как видно, в скобках для группировки команд снова используются && и || .
Скрипт использует коды завершения, чтобы понять, была ли команда успешно выполнена. Если коды завершения используются некорректно, пользователь скрипта может получить неожиданные результаты при неудачном выполнении команды.
Дополнительные коды завершения
Команда exit принимает числа от 0 до 255 . В большинстве случаев можно обойтись кодами 0 и 1 . Однако есть зарезервированные коды, которые обозначают конкретные ошибки. Список зарезервированных кодов можно посмотреть в документации.
Адаптированный перевод статьи Understanding Exit Codes and how to use them in bash scripts by Benjamin Cane. Мнение администрации Хекслета может не совпадать с мнением автора оригинальной публикации.
Linux and Unix exit code tutorial with examples
Tutorial on using exit codes from Linux or UNIX commands. Examples of how to get the exit code of a command, how to set the exit code and how to suppress exit codes.
- August 7, 2016
- Updated May 24, 2023
What is an exit code in the UNIX or Linux shell? ¶
An exit code, or sometimes known as a return code, is the code returned to a parent process by an executable. On POSIX systems the standard exit code is 0 for success and any number from 1 to 255 for anything else.
Exit codes can be interpreted by machine scripts to adapt in the event of successes of failures. If exit codes are not set the exit code will be the exit code of the last run command.
How to get the exit code of a command ¶
To get the exit code of a command type echo $? at the command prompt. In the following example a file is printed to the terminal using the cat command.
cat file.txt hello world echo $? 0
The command was successful. The file exists and there are no errors in reading the file or writing it to the terminal. The exit code is therefore 0 .
In the following example the file does not exist.
cat doesnotexist.txt cat: doesnotexist.txt: No such file or directory echo $? 1
The exit code is 1 as the operation was not successful.
How to use exit codes in scripts ¶
To use exit codes in scripts an if statement can be used to see if an operation was successful.
#!/bin/bash cat file.txt if [ $? -eq 0 ] then echo "The script ran ok" exit 0 else echo "The script failed" >&2 exit 1 fi
If the command was successful the exit code will be 0 and ‘The script ran ok’ will be printed to the terminal.
How to set an exit code ¶
To set an exit code in a script use exit 0 where 0 is the number you want to return. In the following example a shell script exits with a 1 . This file is saved as exit.sh .
Executing this script shows that the exit code is correctly set.
What exit code should I use? ¶
The Linux Documentation Project has a list of reserved codes that also offers advice on what code to use for specific scenarios. These are the standard error codes in Linux or UNIX.
- 1 — Catchall for general errors
- 2 — Misuse of shell builtins (according to Bash documentation)
- 126 — Command invoked cannot execute
- 127 — “command not found”
- 128 — Invalid argument to exit
- 128+n — Fatal error signal “n”
- 130 — Script terminated by Control-C
- 255\* — Exit status out of range
How to suppress exit statuses ¶
Sometimes there may be a requirement to suppress an exit status. It may be that a command is being run within another script and that anything other than a 0 status is undesirable.
In the following example a file is printed to the terminal using cat. This file does not exist so will cause an exit status of 1 .
To suppress the error message any output to standard error is sent to /dev/null using 2>/dev/null .
If the cat command fails an OR operation can be used to provide a fallback — cat file.txt || exit 0 . In this case an exit code of 0 is returned even if there is an error.
Combining both the suppression of error output and the OR operation the following script returns a status code of 0 with no output even though the file does not exist.
#!/bin/bash cat 'doesnotexist.txt' 2>/dev/null || exit 0
Further reading ¶
Tags
Can you help make this article better? You can edit it here and send me a pull request.
See Also
- Linux and Unix cat command tutorial with examples
Aug 4, 2016
Tutorial on using cat, a UNIX and Linux command for concatenating files and printing to standard output. Examples of showing the contents of a file, appending one file to another, and combining multiple files into one. - Linux and Unix grep command tutorial with examples
Aug 3, 2016
Tutorial using grep, a UNIX and Linux command to print lines matching a pattern. Examples of finding text in a file, printing line numbers, counting the number of matches, searching recursively and ignoring case sensitivity. - Linux and Unix tee command tutorial with examples
Jul 28, 2016
Tutorial on using tee, a UNIX and Linux command for copying standard input to standard output and making a copy to one or more files. Examples of writing to a file, appending to a file and writing to a privileged file.