Aprende leyendo en orden

Argumentos y códigos de salida — controlar el script con $1 y exit

Este artículo forma parte del Curso de Linux, con el que dominarás desde cero habilidades prácticas de Linux, desde los comandos básicos hasta los scripts de shell.
Recibe los valores de ./a.sh foo bar con $1 $2 $@ $# $0, aporta un valor predeterminado con ${2:--}, comprueba $? y devuelve éxito o fallo con exit 0 / exit 1 — escribe y ejecuta un script práctico, ilustrado en una terminal del navegador.

Recibir argumentos — $1 / $2 / $0

Los scripts pueden tomar valores cuando los ejecutas.

Los valores que pones después del comando, como ./a.sh foo bar, se llaman argumentos, y dentro del script $1 es el primero y $2 es el segundo.

$0 es el nombre del propio script, $# es el número de argumentos pasados y $@ representa todos ellos en conjunto.

Con estos puedes ejecutar el script con una entrada distinta cada vez en lugar de con valores fijos.

SintaxisSignificadoEjemplo
$1 $2Primer y segundo argumentoecho "$1 then $2"
$0El nombre del propio scriptecho "running $0"
$#Número de argumentos pasadosecho "argc=$#"
$@Todos los argumentos en conjuntoecho "all: $@"
Cómo se asignan los argumentos
./a.sh foo bar$1 = foo$2 = bar$# = 2$@ = foo bar1.º2.ºconteotodos
Los valores que pasas van a $1 $2; $# da el conteo y $@ el conjunto completo.
set -- foo bar                   # fija parámetros posicionales para la demo
echo "1st: $1"                   # foo
echo "2nd: $2"                   # bar
echo "argc: $#"                  # 2
echo "all: $@"                   # foo bar

Escribe un script que reciba valores como argumentos y los imprima tal cual.

① Abre args.sh con vi args.sh, pulsa i para entrar en modo de inserción y pon #!/bin/sh en la primera línea.

② Escribe código que imprima el primer argumento ($1), el segundo ($2), el conteo ($#), todos los argumentos ($@) y el nombre del script ($0).

③ Pulsa Esc, guarda con :wq y luego añade permiso de ejecución.

④ Ejecútalo como ./args.sh foo bar con dos argumentos y comprueba qué valor fue a qué variable. Si te atascas, copia el cuerpo del panel de respuesta y pégalo en el modo de inserción de vi. (Ejecútalo correctamente y aparecerá la explicación).

Linux console
0 / 3 completado(s)
Loading Linux Terminal...

Aportar un valor predeterminado — ${1:-def}

A veces no se pasa ningún argumento.

Si escribes ${1:-default}, se usa default cuando $1 no está definido o está vacío, y se usa el valor dado cuando se proporciona uno.

Esto te permite escribir un script que sigue el argumento cuando se da, y funciona con un valor predeterminado seguro cuando no.

Comprobar $# también te dice si llegó el número esperado de argumentos.

SintaxisSignificadoEjemplo
${1:-def}Usa def cuando $1 no está definidoname=${1:-guest}
${2:-def}Usa def cuando $2 no está definidosep=${2:--}
Cómo se aporta el predeterminado
sep=${2:--}$2 = barsep = bar$2 está vacíosep = - (predeterminado)si se dasi se omiteTal como se daUsa el predeterminado
Con ${2:--}, pasar un segundo valor lo usa, y omitirlo usa el predeterminado -.
set --                           # reproduce la ejecución sin argumentos
echo "${1:-guest}"               # no definido, así que guest
set -- alice                     # ahora el primer argumento está fijado
echo "${1:-guest}"               # tiene un valor, así que alice

Escribe un script que reciba un separador como argumento y use un valor predeterminado cuando se omite.

① Abre format.sh con vi format.sh, pulsa i para entrar en modo de inserción y pon #!/bin/sh en la primera línea.

② Recibe el primer argumento como nombre de objetivo y el segundo como separador, pero escríbelo con ${2:-...} para que se use un predeterminado (por ejemplo -) cuando falte el segundo, y luego imprime el objetivo y el separador.

③ Pulsa Esc, guarda con :wq y luego añade permiso de ejecución.

④ Primero ejecútalo como ./format.sh foo, omitiendo el segundo argumento, y comprueba que el separador recurre al predeterminado. Si te atascas, copia el cuerpo del panel de respuesta y pégalo en el modo de inserción de vi.

Linux console
0 / 3 completado(s)
Loading Linux Terminal...

Devolver éxito o fallo — $? y exit N

Cuando un comando termina devuelve un código de salida, un número de 0 a 255.

Por convención 0 significa éxito y cualquier cosa distinta de 0 significa fallo.

Puedes leer el código de salida del comando anterior con $?.

Para grep es 0 cuando encuentra y 1 cuando no, así que el valor cambia según el resultado.

Desde dentro de un script fijas el código de salida explícitamente con exit N.

Devolver exit 0 para éxito y exit 1 para fallo es la convención común.

Quien lo llama recibe este valor a través de $? o && || y puede usarlo para controlar el flujo, como seguir solo cuando hay éxito.

Si omites exit, se devuelve tal cual el código de salida del último comando ejecutado.

SintaxisSignificadoEjemplo
$?Código de salida del comando anteriorgrep x f; echo $?
exit NTermina el script con el código de salida Nexit 1
Cómo fluyen los códigos de salida
El proceso tiene éxitoexit 0$? = 0El proceso fallaexit 1$? = 1devuelveleedevuelveleeÉxitoFallo
Un script devuelve exit 0 en caso de éxito y exit 1 en caso de fallo, y quien lo llama lee el resultado con $?.
printf 'apple\nbanana\n' > fruits.txt   # crear un archivo de ejemplo
grep apple fruits.txt > /dev/null
echo "found? $?"                          # encontrado, así que 0
grep mango fruits.txt > /dev/null
echo "found? $?"                          # no encontrado, así que 1

Escribe un script que busque en un archivo una palabra dada como argumento y devuelva un código de salida según el resultado.

① Abre search.sh con vi search.sh, pulsa i para entrar en modo de inserción y pon #!/bin/sh en la primera línea.

② En el script, crea un archivo de ejemplo y búscalo por la palabra recibida como primer argumento. Escribe código que imprima un mensaje de éxito y devuelva exit 0 cuando se encuentra, o imprima un mensaje de fallo y devuelva exit 1 cuando no.

③ Pulsa Esc, guarda con :wq y luego añade permiso de ejecución.

④ Ejecútalo como ./search.sh foo bar y luego comprueba el código de salida con echo $?. Si te atascas, copia el cuerpo del panel de respuesta y pégalo en el modo de inserción de vi.

Linux console
0 / 3 completado(s)
Loading Linux Terminal...

Procesar cada argumento por turno — $@ y $#

Cuando el número de argumentos no es fijo, en lugar de escribir $1 $2 uno por uno, recorre $@ con for para procesar tantos como se hayan pasado.

La forma for x in "$@"; do … done los toma de uno en uno, y mostrar el conteo con $# permite que el mismo script maneje cualquier número de argumentos.

Es un patrón común en herramientas que procesan varios archivos juntos.

SintaxisSignificadoEjemplo
"$@"Pasa cada argumento palabra por palabra (para for; necesita comillas dobles)for x in "$@"; do
$#Número de argumentos pasadosecho "count=$#"
Recorrer todos los argumentos
./a.sh foo bar baz$# = 3$@ = foo bar bazfor x in "$@"- foo- bar- bazconteotodosuno por unoimprimebucle con for
Obtén el conteo con $#, luego toma cada argumento de uno en uno con $@ en un bucle for para procesarlos.
set -- foo bar baz               # fija parámetros posicionales para la demo
echo "argc: $#"                  # 3
for x in "$@"; do
  echo "- $x"                    # - foo / - bar / - baz
done

Escribe un script que procese cada argumento pasado de uno en uno y que también muestre el conteo.

① Abre list.sh con vi list.sh, pulsa i para entrar en modo de inserción y pon #!/bin/sh en la primera línea.

② Imprime el número de argumentos con $#, luego toma cada uno por turno con $@ en un bucle for e imprime cada argumento en su propia línea.

③ Pulsa Esc, guarda con :wq y luego añade permiso de ejecución.

④ Ejecútalo como ./list.sh foo bar baz con tres argumentos y comprueba que el conteo y cada argumento se imprimen en orden. Si te atascas, copia el cuerpo del panel de respuesta y pégalo en el modo de inserción de vi.

Linux console
0 / 3 completado(s)
Loading Linux Terminal...
QUIZ

Verificación de conocimientos

Responde cada pregunta una a una.

Pregunta 1¿Qué entra en $2 cuando ejecutas ./a.sh foo bar?

Pregunta 2¿Cuál es el significado correcto de ${1:-guest}?

Pregunta 3¿Cuál lee el código de salida que indica si el comando anterior tuvo éxito?