Linux script error code

Linux script error code

Exit codes are a number between 0 and 255, which is returned by any Unix command when it returns control to its parent process.
Other numbers can be used, but these are treated modulo 256, so exit -10 is equivalent to exit 246 , and exit 257 is equivalent to exit 1 .

These can be used within a shell script to change the flow of execution depending on the success or failure of commands executed. This was briefly introduced in Variables — Part II. Here we shall look in more detail in the available interpretations of exit codes.

Success is traditionally represented with exit 0 ; failure is normally indicated with a non-zero exit-code. This value can indicate different reasons for failure.
For example, GNU grep returns 0 on success, 1 if no matches were found, and 2 for other errors (syntax errors, non-existent input files, etc).

We shall look at three different methods for checking error status, and discuss the pros and cons of each approach.

Firstly, the simple approach:

#!/bin/sh # First attempt at checking return codes USERNAME=`grep "^$:" /etc/passwd|cut -d":" -f1` if [ "$?" -ne "0" ]; then echo "Sorry, cannot find user $ in /etc/passwd" exit 1 fi NAME=`grep "^$:" /etc/passwd|cut -d":" -f5` HOMEDIR=`grep "^$:" /etc/passwd|cut -d":" -f6` echo "USERNAME: $USERNAME" echo "NAME: $NAME" echo "HOMEDIR: $HOMEDIR"

This script works fine if you supply a valid username in /etc/passwd . However, if you enter an invalid code, it does not do what you might at first expect — it keeps running, and just shows:

Why is this? As mentioned, the $? variable is set to the return code of the last executed command. In this case, that is cut . cut had no problems which it feels like reporting — as far as I can tell from testing it, and reading the documentation, cut returns zero whatever happens! It was fed an empty string, and did its job — returned the first field of its input, which just happened to be the empty string.

So what do we do? If we have an error here, grep will report it, not cut . Therefore, we have to test grep ‘s return code, not cut ‘s.

#!/bin/sh # Second attempt at checking return codes grep "^$:" /etc/passwd > /dev/null 2>&1 if [ "$?" -ne "0" ]; then echo "Sorry, cannot find user $ in /etc/passwd" exit 1 fi USERNAME=`grep "^$:" /etc/passwd|cut -d":" -f1` NAME=`grep "^$:" /etc/passwd|cut -d":" -f5` HOMEDIR=`grep "^$:" /etc/passwd|cut -d":" -f6` echo "USERNAME: $USERNAME" echo "NAME: $NAME" echo "HOMEDIR: $HOMEDIR"

This fixes the problem for us, though at the expense of slightly longer code.
That is the basic way which textbooks might show you, but it is far from being all there is to know about error-checking in shell scripts. This method may not be the most suitable to your particular command-sequence, or may be unmaintainable. Below, we shall investigate two alternative approaches.

Читайте также:  Скотт граннеман linux карманный справочник 2019

As a second approach, we can tidy this somewhat by putting the test into a separate function, instead of littering the code with lots of 4-line tests:

#!/bin/sh # A Tidier approach check_errs() < # Function. Parameter 1 is the return code # Para. 2 is text to display on failure. if [ "$" -ne "0" ]; then echo "ERROR # $ : $" # as a bonus, make our script exit with the right error code. exit $ fi > ### main script starts here ### grep "^$:" /etc/passwd > /dev/null 2>&1 check_errs $? "User $ not found in /etc/passwd" USERNAME=`grep "^$:" /etc/passwd|cut -d":" -f1` check_errs $? "Cut returned an error" echo "USERNAME: $USERNAME" check_errs $? "echo returned an error - very strange!"

This allows us to test for errors 3 times, with customised error messages, without having to write 3 individual tests. By writing the test routine once. we can call it as many times as we wish, creating a more intelligent script, at very little expense to the programmer. Perl programmers will recognise this as being similar to the die command in Perl.

As a third approach, we shall look at a simpler and cruder method. I tend to use this for building Linux kernels — simple automations which, if they go well, should just get on with it, but when things go wrong, tend to require the operator to do something intelligent (ie, that which a script cannot do!):

#!/bin/sh cd /usr/src/linux && \ make dep && make bzImage && make modules && make modules_install && \ cp arch/i386/boot/bzImage /boot/my-new-kernel && cp System.map /boot && \ echo "Your new kernel awaits, m'lord."

This script runs through the various tasks involved in building a Linux kernel (which can take quite a while), and uses the && operator to check for success. To do this with if would involve:

#!/bin/sh cd /usr/src/linux if [ "$?" -eq "0" ]; then make dep if [ "$?" -eq "0" ]; then make bzImage if [ "$?" -eq "0" ]; then make modules if [ "$?" -eq "0" ]; then make modules_install if [ "$?" -eq "0" ]; then cp arch/i386/boot/bzImage /boot/my-new-kernel if [ "$?" -eq "0" ]; then cp System.map /boot/ if [ "$?" -eq "0" ]; then echo "Your new kernel awaits, m'lord." fi fi fi fi fi fi fi fi

The && and || operators are the shell’s equivalent of AND and OR tests. These can be thrown together as above, or:

#!/bin/sh cp /foo /bar && echo Success || echo Failed

This code will either echo

depending on whether or not the cp command was successful. Look carefully at this; the construct is

command && command-to-execute-on-success || command-to-execute-on-failure

Only one command can be in each part. This method is handy for simple success / fail scenarios, but if you want to check on the status of the echo commands themselves, it is easy to quickly become confused about which && and || applies to which command. It is also very difficult to maintain. Therefore this construct is only recommended for simple sequencing of commands.

In earlier versions, I had suggested that you can use a subshell to execute multiple commands depending on whether the cp command succeeded or failed:

cp /foo /bar && ( echo Success ; echo Success part II; ) || ( echo Failed ; echo Failed part II )

But in fact, Marcel found that this does not work properly. The syntax for a subshell is:

( command1 ; command2; command3 )

The return code of the subshell is the return code of the final command ( command3 in this example). That return code will affect the overall command. So the output of this script:

cp /foo /bar && ( echo Success ; echo Success part II; /bin/false ) || ( echo Failed ; echo Failed part II )

Is that it runs the Success part (because cp succeeded, and then — because /bin/false returns failure, it also executes the Failure part:

Success Success part II Failed Failed part II

So if you need to execute multiple commands as a result of the status of some other condition, it is better (and much clearer) to use the standard if , then , else syntax.

Читайте также:  Script linux bash server

Источник

Linux script error code

Таблица 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++. Это сделало бы поиск ошибок более простым.

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

Читайте также:  Терминал linux последовательный порт

Примечания

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

Источник

Error handling in Bash scripts

Eraser

Scripting is one of the key tools for a sysadmin to manage a set of day-to-day activities such as running backups, adding users/groups, installing/updating packages, etc. While writing a script, error handling is one of the crucial things to manage.

This article shows some basic/intermediate techniques of dealing with error handling in Bash scripting. I discuss how to obtain the error codes, get verbose output while executing the script, deal with the debug function, and standard error redirection. Using these techniques, sysadmins can make their daily work easy.

Exit status

In Bash scripting, $? prints the exit status. If it returns zero, it means there is no error. If it is non-zero, then you can conclude the earlier task has some issue.

A basic example is as follows:

$ cat myscript.sh #!/bin/bash mkdir learning echo $?

If you run the above script once, it will print 0 because the directory does not exist, therefore the script will create it. Naturally, you will get a non-zero value if you run the script a second time, as seen below:

$ sh myscript.sh mkdir: cannot create directory 'learning': File exists 1

Cloud services

Best practices

It is always recommended to enable the debug mode by adding the -e option to your shell script as below:

$ cat test3.sh !/bin/bash set -x echo "hello World" mkdiir testing ./test3.sh + echo 'hello World' hello World + mkdiir testing ./test3.sh: line 4: mkdiir: command not found

You can write a debug function as below, which helps to call it anytime, using the example below:

$ cat debug.sh #!/bin/bash _DEBUG="on" function DEBUG() < [ "$_DEBUG" == "on" ] && $@ >DEBUG echo 'Testing Debudding' DEBUG set -x a=2 b=3 c=$(( $a + $b )) DEBUG set +x echo "$a + $b = $c"
$ ./debug.sh Testing Debudding + a=2 + b=3 + c=5 + DEBUG set +x + '[' on == on ']' + set +x 2 + 3 = 5

Standard error redirection

You can redirect all the system errors to a custom file using standard errors, which can be denoted by the number 2. Execute it in normal Bash commands, as demonstrated below:

$ mkdir users 2> errors.txt $ cat errors.txt mkdir: cannot create directory ‘users’: File exists

Most of the time, it is difficult to find the exact line number in scripts. To print the line number with the error, use the PS4 option (supported with Bash 4.1 or later). Example below:

$ cat test3.sh #!/bin/bash PS4='LINENO:' set -x echo "hello World" mkdiir testing

You can easily see the line number while reading the errors:

$ /test3.sh 5: echo 'hello World' hello World 6: mkdiir testing ./test3.sh: line 6: mkdiir: command not found

Wrap up

Managing errors is a key skill for administrators when writing scripts. These tips should help make your life easier when troubleshooting Bash scripts or even general commands.

Источник

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