Linux коды завершения процессов

Работа с linux. Exit codes.

Привет. Сегодня ещё один важный момент про работу с Linux — обработка кодов завершения процессов. У меня на данный момент стоит Ubuntu 18, все написанное дальше тестировалось на этой системе. Нюансы могут отличаться, но суть должна остаться неизменной. Код завершения (exit code) — число от 0 до 255, возвращаемое при завершении процесса в родительский процесс. Это число может быть интерпретировано программой и распознано как успех или провал.

Как правило, 0 код — успех, все остальные сигнализируют о разных причинах провала.

Как их отслеживать?

Получить код завершения предыдущего процесса можно с помощью команды `$?`

1 — стандартный код для общих ошибок.

В данном случае ошибка — cat: /some_file.txt: Нет такого файла или каталога.

Коды завершения и конвейеры (pipelines)

У нас есть два оператора, позволяющие взаимодействовать с кодами завершения в конвейере — это `&&` и `||`

В теории `&&` можно было бы реализовать с помощью проверки условий if например так:

Или использовать `if [ $? -ne 0 ]; then` для `||`, но для конвейера такое решение не годится.

`&&`действует как логические И. Оператор запускает следующую команду, если код завершения предыдущей 0.

`||` действует как логическое ИЛИ. Оператор запускает следующую команду, если предыдущая вернула код отличный от 0.

Хоть решение с if не подойдет для какого-нибудь сложного конвейера, с несколькими уровнями вложений, его удобно использовать для файлов-скриптов.

Коды завершения и .sh файлы

Мы конечно можем сплетать замысловатые цепочки команд в завораживающие конвейеры. Ощущаешь безграничную власть, когда можешь удержать такое в голове, но обычно это непонятно остальным и становится непонятно тебе спустя какое-то время (чаще всего в самый неподходящий момент).

Поэтому обычно && || используются в составе .sh скриптов для улучшения читаемости и сокращения связанных команд. Рассмотрим пару вариантов, которые я использовал в работе.

Нюанс в том, что .sh скрипт движется дальше и командой $? вы получите только код завершения последней команды. Поэтому если команда, которая может вернуть ошибку где-то в середине, то код затеряется и дальше его видно не будет. Если такой скрипт участвует в конвейере, то следующая команда получит ложный сигнал.

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

Если у вас есть несколько команд и важна правильность выполнения всего скрипта, но при этом нужно, чтобы скрипт проходил полностью (например в конце расположен код, удаляющий созданные вначале файлы вне зависимости от результатов тестов) можно поставить счетчик и возвращать 1 в случае, если он больше 0 уже после чистки.

Читайте также:  Автозагрузка линукс как поставить

Второй вариант — если нужно сразу прерывать скрипт при провале. Напишем небольшую проверочную функцию и будем запускать её после важных скриптов (так можно дополнительно кастомизировать сообщение). Получится что-то вроде обработчика исключений.

Чтобы её применить нужно указать `check $? ‘exception text’` после исполняемой команды. Первым аргументом вы передаете код завершения предыдущего процесса, а вторым ваш текст ошибки. Важно, что мы выходим с тем же кодом ошибки, который был передан от последнего проверяемого процесса. Отредактируем наш скрипт:

На этом все, надеюсь вы так же оцените удобство работы с командной строкой и этот инструмент вам поможет перейти на новый уровень)

Источник

Linux коды завершения процессов

Таблица C-1. «Зарезервированные» коды завершения

Код завершения Смысл Пример Примечание
1 разнообразные ошибки let «var1 = 1/0» различные ошибки, такие как «деление на ноль» и пр.
2 согласно документации к Bash — неверное использование встроенных команд Встречаются довольно редко, обычно код завершения возвращается равным 1
126 вызываемая команда не может быть выполнена возникает из-за проблем с правами доступа или когда вызван на исполнение неисполняемый файл
127 «команда не найдена» Проблема связана либо с переменной окружения $PATH, либо с неверным написанием имени команды
128 неверный аргумент команды exit exit 3.14159 команда exit может принимать только целочисленные значения, в диапазоне 0 — 255
128+n фатальная ошибка по сигналу «n» kill -9 $PPID сценария $? вернет 137 (128 + 9)
130 завершение по Control-C Control-C — это выход по сигналу 2, (130 = 128 + 2, см. выше)
255* код завершения вне допустимого диапазона exit -1 exit может принимать только целочисленные значения, в диапазоне 0 — 255

Согласно этой таблице, коды завершения 1 — 2, 126 — 165 и 255 [1] имеют предопределенное значение, поэтому вам следует избегать употребления этих кодов для своих нужд. Завершение сценария с кодом возврата exit 127, может привести в замешательство при поиске ошибок в сценарии (действительно ли он означает ошибку «команда не найдена» ? Или это предусмотренный программистом код завершения?). В большинстве случаев, программисты вставляют exit 1, в качестве реакции на ошибку. Так как код завершения 1 подразумевает целый «букет» ошибок, то в данном случае трудно говорить о какой либо двусмысленности, хотя и об информативности — тоже.

Не раз предпринимались попытки систематизировать коды завершения (см. /usr/include/sysexits.h), но эта систематизация предназначена для программистов, пишущих на языках C и C++. Автор документа предлагает ограничить коды завершения, определяемые пользователем, диапазоном 64 — 113 (и, само собой разумеется — 0, для обозначения успешного завершения), в соответствии со стандартом C/C++. Это сделало бы поиск ошибок более простым.

Читайте также:  Linux посмотреть установленные пакеты centos

Обращение к переменной $?, из командной строки, после завершения работы сценария, дает результат, в соответствии с таблицей, приведенной выше, но только для Bash или sh . Под управлением csh или tcsh значения могут в некоторых случаях отличаться.

Примечания

Указание кода завершения за пределами установленного диапазона, приводит к возврату ошибочных кодов. Например, exit 3809 вернет код завершения, равный 225 .

Источник

How to use Linux shell command exit codes

You can use the numeric codes returned by shell scripts or Ansible playbooks to identify problems and test the code.

Exit codes

When you execute a command in Linux, it generates a numeric return code. This happens whether you’re running the command directly from the shell, from a script, or even from an Ansible playbook. You can use those return codes to handle the result of that command properly.

What the return codes mean

When running commands at a shell prompt, the special variable $? contains a number that indicates the result of the last command executed.

A zero ( 0 ) means everything went fine. Anything else means there is a problem.

A value of 1 generically indicates that some error has happened.

$ who admin2 :1 2022-03-15 10:14 (:1) $ echo $? 0 $ who | grep thisstringdoesnotexist $ echo $? 1

In the example above, I executed the who command, which showed that I am admin2.

Immediately after that, I executed echo $? , and it returned zero because the previous command was executed successfully.

Then I executed the same who command (which I know is working fine) and piped that to grep with the non-existing argument. This time the $? variable contains a 1 .

Why? It’s because the last command executed was grep , which returns 1 when it cannot find the argument in its input.

$ls myfile.cfg ls: cannot access 'myfile.cfg': No such file or directory $echo $? 2

Here I tried to list a file that doesn’t exist. Then when I entered echo $? I got 2 , which is how the ls command indicates that the argument is not a file or directory name.

Customize the return code

You can also use the exit command from a shell script to customize the return code to the caller script.

The following script illustrates this:

#!/bin/bash if [ ! -f myfile.cfg ]; then echo The file does not exist and we display an error exit 64 fi echo The file exists and we will do something echo "(Not really doing anything, but this is where we could do it)" exit 0
$./myscrypt.sh The file does not exist and we display an error $echo $? 64 $touch myfile.cfg $./myscrypt.sh The file exists and we will do something (Not really doing anything, but this is where we could do it) $echo $? 0

Training & certification

In this script, I explicitly provide the exit code for the failed and for the successful cases. Some observations:

  1. If I do not explicitly use exit 0 , the return code from myscript.sh will be the return code from the last command executed inside it. This could be what I want, but here I wanted to state the return code pretty clearly inside the script.
  2. I used 64 as an arbitrary return code for the error condition. The Advanced Bash-Scripting Guide offers some guidelines about exit code values.
Читайте также:  Linux on my samsung debian

Test the return code with a shell script

If you need to test the return code of a command you invoked on your shell script, you just need to test the $? variable immediately after the command executes.

#!/bin/bash # A snipet from a shell script . # Next we will invoke a command or another shell script ./myscript.sh RETURN=$? if [ $RETURN -eq 0 ]; then echo "The script myscript.sh was executed successfuly" exit 0 else echo "The script myscript.sh was NOT executed successfuly and returned the code $RETURN" exit $RETURN fi 

In this example, after invoking my command or script, I saved the exit code from $? on a variable for further utilization. (Again, $? returns the status of the last command, so you need to be careful if you run more commands—even a simple echo .).

Test the return code with an Ansible playbook

It is recommended to avoid running shell commands from an Ansible playbook if there is an Ansible module that performs the same action. This is especially because with a module you have better odds of being idempotent.

[ Ready to start automating? Check out this Ansible quick start series. ]

To illustrate how to handle return codes from a shell command, check this simple playbook:

--- - name: Executes a shell script hosts: localhost gather_facts: no tasks: - name: Execute the shell script shell: ./myscript.sh ignore_errors: true register: result - name: Shows the result of executing the script debug: msg: - "Return code. >" - ">"

This is the Ansible playbook executed when a script returns an error:

[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' PLAY [Executes a shell script] ***************************************************************************************** TASK [Execute the shell script] **************************************************************************************** fatal: [localhost]: FAILED! => . ignoring TASK [Shows the result of executing the script] ************************************************************************ ok: [localhost] => < "msg": [ "Return code. 64", [ "The file does not exist and we display an error" ] ] >PLAY RECAP ************************************************************************************************************* localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1 

Источник

Оцените статью
Adblock
detector