Tutoriales

Cómo usar los códigos de salida de comandos de shell de Linux

Cuando ejecuta un comando en Linux, genera un código de retorno numérico. Esto sucede ya sea que esté ejecutando el comando directamente desde el shell, desde un script o incluso desde un libro de jugadas de Ansible. Puede usar esos códigos de retorno para manejar el resultado de ese comando correctamente.

Qué significan los códigos de retorno

Al ejecutar comandos en un indicador de shell, la variable especial $? contiene un número que indica el resultado de la último comando ejecutado.

[ Download now: A sysadmin’s guide to Bash scripting. ]

un cero () significa que todo salió bien. Cualquier otra cosa significa que hay un problema.

Un valor de 1 generalmente indica que alguno ha ocurrido un error.

$ who
admin2   :1           2022-03-15 10:14 (:1)

$ echo $?
0

$ who | grep thisstringdoesnotexist

$ echo $?
1

En el ejemplo anterior, ejecuté el who comando, que mostró que soy administrador2.

Inmediatamente después de eso, ejecuté echo $?y devolvió cero porque el comando anterior se ejecutó con éxito.

Luego ejecuté lo mismo. who comando (que sé que funciona bien) y canalizó eso a grep con el argumento inexistente. Esta vez el $? variable contiene un 1.

¿Por qué? es porque el ultimo el comando ejecutado fue grepque vuelve 1 cuando no puede encontrar el argumento en su entrada.

[ Free eBook: Manage your Linux environment for success ]

Aquí hay otro ejemplo:

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

$echo $?
2

Aquí traté de enumerar un archivo que no existe. Entonces cuando entré echo $? Obtuve 2que es como el ls El comando indica que el argumento no es un nombre de archivo o directorio.

Personaliza el código de retorno

También puede utilizar el exit comando desde un script de shell para personalizar el código de retorno al script de la persona que llama.

El siguiente script ilustra esto:

#!/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

En este script, proporciono explícitamente el código de salida para los casos fallidos y exitosos. Algunas observaciones:

  1. Si no uso explícitamente exit 0el código de retorno de myscript.sh será el código de retorno del ultimo comando ejecutado en su interior. Esto podría ser lo que quiero, pero aquí quería indicar claramente el código de retorno dentro del script.
  2. solía 64 como un código de retorno arbitrario para la condición de error. La Guía avanzada de secuencias de comandos de Bash ofrece algunos directrices sobre los valores del código de salida.

Pruebe el código de retorno con un script de shell

Si necesita probar el código de retorno de un comando que invocó en su script de shell, solo necesita probar el $? variable inmediatamente después de que se ejecuta el comando.

#!/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 

En este ejemplo, después de invocar mi comando o secuencia de comandos, guardé el código de salida de $? en una variable para su posterior utilización. (Otra vez, $? devuelve el estado de la ultimo comando, por lo que debe tener cuidado si ejecuta más comandos, incluso uno simple echo.).

Pruebe el código de retorno con un libro de jugadas de Ansible

Se recomienda evitar ejecutar comandos de shell desde un libro de jugadas de Ansible si hay un módulo Ansible que realiza la misma acción. Esto se debe especialmente a que con un módulo tienes mejores probabilidades de ser idempotente.

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

Para ilustrar cómo manejar los códigos de retorno de un comando de shell, consulte este sencillo libro de jugadas:

---
- 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...: {{ result.rc }}"
      - "{{ result.stdout_lines }}"

Este es el libro de jugadas de Ansible que se ejecuta cuando un script devuelve un 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! => {"changed": true, "cmd": "./myscript.sh", "delta": "0:00:00.003315", "end": "2022-06-13 15:35:06.123759", "msg": "non-zero return code", "rc": 64, "start": "2022-06-13 15:35:06.120444", "stderr": "", "stderr_lines": [], "stdout": "The file does not exist and we display an error", "stdout_lines": ["The file does not exist and we display an error"]}
...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   

Definí la tarea para ignorar el error, por lo que en la siguiente tarea, simplemente puedo mostrar el código de retorno y el mensaje del script. También podría haber manejado el código de retorno en mi libro de jugadas de Ansible usando el result.rc variable con alguna combinación de assert módulo o agregando el when condición a otra tarea.

Terminando

Ahora tiene algunos conocimientos sobre los códigos de retorno de los comandos y scripts invocados por sus scripts de shell y playbooks de Ansible. Espero que esto te ayude a manejar tus scripts más fácilmente.

Publicaciones relacionadas

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Botón volver arriba