← Automatización con Scripts en Bash Bloque 2 · Variables y datos · Tema 5 de 42

Tema 5

Variables

Un script que no guarda datos solo puede repetir siempre lo mismo. Con variables puede recordar una ruta, la fecha de hoy, la salida de un comando o un valor que le pasó quien lo ejecuta, y usarlos donde haga falta. Este tema explica cómo se crean y se leen las variables en Bash, qué papel juegan las comillas, qué diferencia hay entre una variable del script y una del entorno, y cómo proteger los valores que no deben cambiar.

1. Un nombre para un dato

Una variable es un nombre asociado a un valor. En Bash, ese valor es siempre una cadena de texto: no hay tipos distintos para números, fechas o rutas. Cuando hace falta tratar el texto como número, es la operación la que lo interpreta así, como veremos en el tema 7.

Las variables cumplen en un script tres funciones que ya aparecieron en los temas anteriores:

Los nombres pueden contener letras, dígitos y guiones bajos, y no pueden empezar con un dígito. Distinguen mayúsculas de minúsculas: archivo, Archivo y ARCHIVO son tres variables distintas. Las letras con tilde y la eñe no están permitidas.

Nombre¿Válido?Comentario
destino, total_copiados, dir2SíLa forma recomendada para variables de trabajo (tema 4).
DIAS_RETENCIONSíEn mayúsculas: constantes y configuración.
_tmpSíVálido, aunque poco habitual.
2dirNoEmpieza con un dígito.
fecha-inicioNoEl guion no está permitido; se usa el guion bajo.
añoNoLa eñe no está permitida.

2. Asignar

Una variable se crea asignándole un valor, con la forma nombre=valor. No hace falta declararla antes. Como vimos en el tema 3, la regla esencial es que no puede haber espacios alrededor del =, porque Bash cortaría la línea en palabras y tomaría la primera como un comando.

terminal
$ destino=/respaldos                     # crea la variable
$ destino=/mnt/respaldos                 # reemplaza el valor
$ vacia=                                 # una variable con valor vacío
$ dias=30 formato=gzip                   # varias asignaciones en una línea

Al asignar no se escribe el signo $: el $ sirve para leer el valor, no para nombrar la variable. Escribir $destino=/otra no asigna nada; Bash reemplaza $destino por su valor y trata de ejecutar el resultado como un comando:

terminal
$ $destino=/otra
bash: /mnt/respaldos=/otra: No such file or directory

3. Leer el valor

Para usar el valor se antepone $ al nombre. La forma completa es ${nombre}, con llaves, y la abreviada $nombre funciona cuando el carácter que sigue no puede formar parte de un nombre:

terminal
$ archivo=ventas
$ echo "$archivo.csv"                    # el punto no es parte de un nombre
ventas.csv
$ echo "$archivo_2026.csv"               # _2026 sí: busca la variable archivo_2026
.csv
$ echo "${archivo}_2026.csv"
ventas_2026.csv

Las llaves son también la puerta de entrada a las transformaciones del tema 6: ${archivo:-predeterminado}, ${#archivo}, ${archivo%.csv}. Y, como establecimos en el tema 3, al leer una variable se la pone entre comillas dobles, salvo que se quiera a propósito que se divida en palabras: "$archivo", no $archivo.

4. Comillas al asignar

En el lado derecho de una asignación, Bash no divide en palabras ni expande comodines, de modo que copia=$original funciona aunque original tenga espacios. Pero eso vale para el resultado de las expansiones, no para el texto escrito en la línea. Si el valor literal tiene espacios, la línea se corta antes, en la etapa 1:

terminal
$ saludo=hola mundo                      # asigna «hola» solo para el comando «mundo»
bash: mundo: command not found
$ saludo="hola mundo"                    # correcto
$ copia=$saludo                          # también correcto: el resultado no se divide
$ echo "$copia"
hola mundo

El tipo de comillas decide qué se expande dentro del valor:

AsignaciónValor guardadoCuándo usarla
msg="Hola, $USER"Hola, anaCuando el valor incluye otras variables o sustituciones. Es la forma habitual.
msg='Hola, $USER'Hola, $USERCuando el valor es literal: patrones de grep, programas de awk, textos con $.
msg=$'línea 1\nlínea 2'Dos líneasCuando el valor incluye caracteres especiales como el salto de línea o el tabulador.
ruta="$dir/$archivo"Las dos variables unidas por /Para construir rutas y nombres a partir de partes.

Una pauta práctica: aunque el lado derecho de una asignación no necesite comillas para protegerse de la división, ponerlas siempre (copia="$original") evita tener que recordar la excepción, y hace el script más uniforme.

5. Guardar la salida de un comando

La sustitución de comandos, $(comando), ejecuta un comando y se reemplaza por lo que este escribió en su salida estándar. Asignada a una variable, es la forma de guardar un resultado para usarlo después:

terminal
$ hoy="$(date +%F)"
$ equipo="$(hostname)"
$ archivos="$(ls ~/docs | wc -l)"
$ echo "$equipo tiene $archivos documentos al $hoy"
equipo tiene 14 documentos al 2026-10-14

Tres detalles de su comportamiento conviene conocer:

DetalleConsecuencia
Se eliminan los saltos de línea finalesLa salida de date termina en un salto de línea, pero la variable no lo guarda. Los saltos de línea intermedios sí se conservan.
Solo se captura la salida estándarLos mensajes de error siguen yendo a la pantalla. Para capturarlos también: $(comando 2>&1).
Se ejecuta en un proceso aparteLas variables que el comando modifique dentro de $( ) no cambian en el script. Y cada sustitución cuesta crear un proceso.

Una salida de varias líneas se guarda completa, y las comillas al leerla deciden si se conserva su forma:

terminal
$ v="$(printf 'uno\ndos\n\n\n')"
$ declare -p v                            # muestra el valor exacto
declare -- v=$'uno\ndos'
$ echo "$v"
uno
dos
$ echo $v                                # sin comillas, el salto de línea divide palabras
uno dos

Hay algo más: una asignación con sustitución de comandos toma el código de salida del comando. Eso permite guardar la salida y saber, en la misma línea, si el comando funcionó. Lo usaremos mucho a partir del tema 10:

terminal
$ if salida="$(ls /no/existe 2>&1)"; then echo "bien"; else echo "falló: $salida"; fi
falló: ls: cannot access '/no/existe': No such file or directory
Las comillas invertidas

En scripts antiguos verás la sustitución escrita con comillas invertidas: hoy=`date +%F`. Hace lo mismo, pero no se puede anidar con facilidad y se confunde con las comillas simples. Como vimos en el tema 4, se usa siempre $( ).

6. Agregar al final: +=

El operador += agrega texto al final del valor actual, sin repetir el nombre de la variable. Es útil para construir un valor de a poco, por ejemplo un mensaje que se completa a medida que el script avanza:

terminal
$ informe="Respaldo del $(date +%F):"
$ informe+=" docs OK"
$ informe+=", fotos OK"
$ echo "$informe"
Respaldo del 2026-10-14: docs OK, fotos OK
$ ruta="/var/log"; ruta+="/app"           # equivale a ruta="$ruta/app"

Para una variable común, += une texto: n=5; n+=1 deja 51, no 6. Para sumar se usa la aritmética del tema 7. Con los arrays del tema 8, += agrega elementos.

7. Las variables que Bash ya trae

Al iniciar, Bash define un conjunto de variables, algunas heredadas del entorno y otras propias. Estas son las más útiles en un script:

VariableContieneUso típico en un script
HOMEEl directorio personal del usuario.Rutas que no dependan de un usuario concreto: "$HOME/respaldos".
USEREl nombre del usuario.Mensajes y registros.
PWDEl directorio actual.Lo mismo que $(pwd), sin crear un proceso.
HOSTNAMEEl nombre del equipo.Identificar en qué máquina se generó un informe.
0La ruta con que se invocó el script.Mensajes de uso: "${0##*/}" (temas 2 y 4).
$El número de proceso de la shell.Nombres únicos para archivos temporales, aunque es mejor mktemp (tema 24).
?El código de salida del último comando.Saber si algo falló (tema 10).
RANDOMUn número entero aleatorio entre 0 y 32767, distinto en cada lectura.Esperas al azar para no sobrecargar un servidor: sleep $(( RANDOM % 60 )).
SECONDSLos segundos transcurridos desde que empezó la shell.Medir cuánto tardó el script.
LINENOEl número de la línea que se está ejecutando.Mensajes de error que indiquen dónde ocurrió.
BASH_VERSIONLa versión de Bash.Comprobar que se cuenta con una versión suficiente.

Las tres primeras vienen del entorno y pueden faltar en contextos especiales, como algunos servicios del sistema; las demás las mantiene Bash. SECONDS es un buen ejemplo de lo que aportan:

al final de un script
printf '%s: terminado en %d segundos\n' "${0##*/}" "$SECONDS"

8. Vacías e inexistentes

Una variable puede estar en tres situaciones: tener un valor, existir con valor vacío o no existir. Al leerla, las dos últimas se ven igual: Bash expande una variable inexistente como cadena vacía, sin ningún aviso.

terminal
$ destino=/respaldos
$ echo "Copiando a [$destion]"             # nombre mal escrito
Copiando a []

Ese silencio es peligroso. Un rm -rf "$directorio/"* con el nombre de la variable mal escrito se convierte en rm -rf /*. Bash ofrece una opción para convertir ese silencio en un error: set -u, que hace que leer una variable inexistente detenga el script.

terminal
$ bash -c 'set -u; destino=/respaldos; echo "Copiando a $destion"'
bash: line 1: destion: unbound variable

Es la u de set -euo pipefail, la línea que pusimos en todos los scripts desde el tema 2, y una razón más para usarla. Con set -u activo, las variables que pueden no existir se leen con un valor por defecto, "${variable:-}", como veremos en el tema 6. Para distinguir si una variable existe, aunque esté vacía, Bash tiene la prueba [[ -v nombre ]], que se escribe sin $:

terminal
$ unset q; [[ -v q ]] && echo existe || echo "no existe"
no existe
$ q=; [[ -v q ]] && echo existe || echo "no existe"
existe

9. Variables de shell y de entorno

Las variables que crea un script viven dentro de su proceso. Cuando el script ejecuta otro programa, ese programa no las ve, salvo que se hayan exportado. El tema 34 del curso de Terminal explicó esta distinción para la shell interactiva; en un script tiene la misma lógica:

Variable de shellVariable de entorno
Cómo se creadestino=/respaldosexport LC_ALL=C
Quién la veSolo el script (o la shell) que la creó.El script y todos los programas que ejecute, que reciben una copia.
Uso típicoLos datos de trabajo del script: casi todas.Configuración que deben leer otros programas: idioma, zona horaria, rutas.
Un script tiene una variable de shell, destino, y una variable exportada, LC_ALL. Al ejecutar un proceso hijo, este recibe una copia de LC_ALL pero no de destino, y los cambios que haga el hijo no vuelven al script copia del entorno nada vuelve Tu script destino=/respaldos variable de shell export LC_ALL=C variable de entorno Proceso hijo sort, otro script… LC_ALL=C recibe una copia destino: no existe no fue exportada
El entorno se copia hacia abajo, al crear cada proceso, y nunca hacia arriba. Un programa hijo no puede cambiar las variables del script que lo ejecutó.
terminal
$ x=fuera
$ bash -c 'echo "el hijo ve: [$x]"'
el hijo ve: []
$ export x
$ bash -c 'echo "el hijo ve: [$x]"'
el hijo ve: [fuera]

La copia va en un solo sentido. De ahí una consecuencia que conviene tener presente: un script no puede cambiar las variables de la shell desde la que lo ejecutaste. Si un script hace export RUTA=/algo, al terminar RUTA desaparece con él. Para modificar la shell actual, el archivo debe cargarse con source, como vimos en el tema 2.

10. export

export marca una variable para que pase al entorno de los programas que se ejecuten a continuación. Puede marcarse una variable existente o crearla y marcarla a la vez:

formas de export
export LC_ALL=C                     # crear y exportar
TZ=America/Argentina/Buenos_Aires
export TZ                           # exportar una existente
export -n TZ                        # dejar de exportarla (sigue existiendo)
LC_ALL=C sort datos.txt             # exportarla solo para un comando

La última forma, una asignación delante de un comando, es la más precisa: la variable existe en el entorno de ese comando y en ningún otro lado, y el script no queda modificado. Es la preferible cuando la configuración afecta a un solo comando.

En un script, la mayoría de las variables no deben exportarse. Exportar solo hace falta cuando otro programa tiene que leer la variable. Algunos casos típicos:

VariableQué controlaPor qué se exporta en un script
LC_ALL=CEl idioma y el formato regional de los programas.Que sort, grep o date den siempre la misma salida, en cualquier máquina, y no dependan del idioma de quien ejecuta.
TZLa zona horaria.Que las fechas de un informe estén en una zona concreta, sea cual sea la del servidor.
PATHDónde se buscan los comandos.Que el script funcione igual desde cron, que usa un PATH reducido (tema 34).
TMPDIRDónde crean archivos temporales muchos programas.Usar un disco con más espacio que /tmp.

Para ver qué variables están en el entorno se usa env o printenv; printenv NOMBRE muestra una sola.

11. Configurar un script desde el entorno

El entorno también funciona en la otra dirección: es una forma cómoda de pasarle configuración a un script sin agregarle opciones. El script lee una variable de entorno y, si no está definida, usa un valor por defecto. La expansión ${VARIABLE:-valor}, que estudiaremos en detalle en el tema 6, hace exactamente eso:

respaldo · configuración
readonly DESTINO="${DESTINO:-/respaldos}"
readonly DIAS="${DIAS:-30}"
terminal
$ respaldo ~/proyecto                         # valores por defecto
Respaldo creado en /respaldos (se conservan 30 días)
$ DESTINO=/mnt/usb DIAS=7 respaldo ~/proyecto   # solo para esta ejecución
Respaldo creado en /mnt/usb (se conservan 7 días)

Es la misma convención que siguen muchos programas: EDITOR, PAGER o LANG son variables de entorno que configuran su comportamiento. Para un script tiene dos ventajas: no hace falta escribir el análisis de opciones, y la configuración puede fijarse en un solo lugar, como la tabla de cron, para todas sus ejecuciones. Cuando un script admite variables de entorno, conviene documentarlas en la cabecera.

12. readonly: valores que no cambian

Las constantes de un script, como el directorio de destino o el plazo de retención, no deberían cambiar después de definirse. readonly lo garantiza: cualquier intento posterior de modificar la variable falla con un error.

terminal · un script con readonly DIAS=30
$ cat constante.sh
#!/usr/bin/env bash
readonly DIAS=30
DIAS=40
echo "Se conservan $DIAS días"
$ ./constante.sh
./constante.sh: line 3: DIAS: readonly variable
Se conservan 30 días

La asignación falló y la variable conservó su valor. Sin set -e, el script siguió adelante; con él, se habría detenido en la línea 3. Una variable de solo lectura tampoco puede eliminarse con unset, y dura hasta que termina el script.

¿Para qué protegerse de uno mismo? Porque en un script largo, o en uno que carga bibliotecas con source, es fácil reutilizar sin querer un nombre ya usado. readonly convierte ese descuido en un error visible, en el momento en que ocurre. La convención es usarlo con las constantes en mayúsculas de la parte de configuración, como en la estructura del tema 2.

13. declare: inspeccionar y dar atributos

El comando declare crea variables con atributos especiales y, sobre todo, permite ver exactamente qué contiene una variable. declare -p nombre muestra la variable tal como habría que escribirla para recrearla, con sus atributos y su valor entrecomillado:

terminal
$ nombre="Ana María"
$ declare -p nombre
declare -- nombre="Ana María"
$ export nombre
$ declare -p nombre
declare -x nombre="Ana María"
$ declare -p DIAS
declare -r DIAS="30"

Cuando no sabes qué contiene realmente una variable, declare -p es más fiable que echo: muestra los espacios al principio y al final, los saltos de línea y los caracteres invisibles, como el retorno de carro de los archivos de Windows, que aparece como \r.

Las letras de declare son los atributos de la variable:

OpciónAtributoEquivale a
-xExportada al entorno.export
-rSolo lectura.readonly
-iEntera: lo que se asigna se evalúa como expresión aritmética.—
-l, -uConvierte el valor a minúsculas o mayúsculas al asignarlo.—
-a, -AArray indexado o asociativo.Tema 8

Dentro de una función, declare crea variables locales, igual que local (tema 18). El atributo -i conviene usarlo con cuidado: hace que n=2*4 guarde 8 y que += sume en lugar de concatenar, y ese cambio de comportamiento, invisible en el punto donde se asigna, confunde a quien lee el script. Para calcular, preferiremos la aritmética explícita del tema 7.

14. unset: eliminar una variable

unset nombre elimina una variable: deja de existir, que no es lo mismo que quedar vacía. Se usa poco en scripts, porque las variables desaparecen solas cuando el script termina. Tiene dos usos razonables: quitar del entorno una variable antes de ejecutar un programa que no debe recibirla, y dejar en un estado conocido una variable que podría venir con un valor heredado.

terminal
$ unset CDPATH                            # una variable heredada que altera el comportamiento de cd
$ env -u LANG programa                    # ejecutar un programa sin LANG en su entorno

15. Un script completo

Reunamos lo visto en un script que muestra un resumen del estado del equipo. Usa constantes configurables desde el entorno, guarda en variables la salida de varios comandos y termina con un código distinto de cero si el disco está demasiado lleno, de modo que pueda usarse desde cron para dar un aviso:

informe-equipo
#!/usr/bin/env bash
#
# informe-equipo — muestra un resumen del estado del equipo.
#
# Uso:      informe-equipo
# Entorno:  UMBRAL_DISCO  porcentaje de uso del disco que se considera
#                         excesivo (por defecto, 90)
# Salida:   0 si el disco está bajo el umbral; 1 si lo supera.
#
set -euo pipefail

readonly UMBRAL="${UMBRAL_DISCO:-90}"
export LC_ALL=C                    # salida de df y free igual en cualquier idioma

equipo="$(hostname)"
fecha="$(date '+%Y-%m-%d %H:%M')"
nucleo="$(uname -r)"
sesiones="$(who | wc -l)"
uso_disco="$(df --output=pcent / | tail -1 | tr -dc '0-9')"
memoria_libre="$(free -h | awk '/^Mem:/ {print $7}')"

printf 'Informe de %s (%s)\n' "$equipo" "$fecha"
printf '  Núcleo:         %s\n' "$nucleo"
printf '  Sesiones:       %s\n' "$sesiones"
printf '  Disco raíz:     %s %%\n' "$uso_disco"
printf '  Memoria libre:  %s\n' "$memoria_libre"

if (( uso_disco >= UMBRAL )); then
  printf '%s: el disco raíz supera el %s %%\n' "${0##*/}" "$UMBRAL" >&2
  exit 1
fi
terminal
$ informe-equipo
Informe de equipo (2026-10-14 16:20)
  Núcleo:         6.8.0-45-generic
  Sesiones:       2
  Disco raíz:     61 %
  Memoria libre:  5.1Gi
$ UMBRAL_DISCO=50 informe-equipo; echo "código: $?"
Informe de equipo (2026-10-14 16:20)
  …
informe-equipo: el disco raíz supera el 50 %
código: 1

Algunos detalles que vale la pena mirar:

16. Errores frecuentes

LíneaQué ocurreForma correcta
destino = /respaldosdestino: command not founddestino=/respaldos
$destino=/respaldosIntenta ejecutar el valor anterior seguido de =/respaldos.destino=/respaldos
saludo=hola mundomundo: command not foundsaludo="hola mundo"
msg='Hola, $USER'Guarda el texto $USER, sin reemplazar.msg="Hola, $USER"
dir="~/datos"Guarda la virgulilla literal; cd "$dir" falla.dir="$HOME/datos"
echo "$archivo_v2"Lee la variable archivo_v2, que no existe."${archivo}_v2"
n=5; n+=1Deja 51.n=$(( n + 1 )) (tema 7)
PATH="$1"El script se queda sin comandos.Un nombre en minúsculas: ruta="$1"
Un nombre mal escrito al leerSe expande vacío, sin aviso.set -u y ShellCheck (SC2154)
export en un script para cambiar la shellLa variable desaparece al terminar el script.Cargar el archivo con source.

17. Resumen

18. Preguntas de repaso

Intenta responder cada una antes de abrir la respuesta.

1. ¿Qué tipo de dato guarda una variable de Bash?

Siempre una cadena de texto. No hay tipos distintos para números: es la operación, por ejemplo la aritmética de $(( )), la que interpreta el texto como número.

2. ¿Cuáles de estos nombres son válidos: total, 2total, total-final, total_final, TOTAL?

Son válidos total, total_final y TOTAL (que es otra variable, distinta de total). 2total empieza con un dígito y total-final contiene un guion.

3. ¿Qué ocurre al ejecutar saludo=hola mundo?

Bash corta la línea en dos palabras. La primera es una asignación que se aplica solo al comando siguiente, y la segunda, mundo, se toma como el comando. El resultado es mundo: command not found, y saludo no queda definida.

4. Con USER=ana, ¿qué contiene m en cada caso: m="Hola $USER" y m='Hola $USER'?

En el primero, Hola ana: las comillas dobles permiten expandir la variable. En el segundo, el texto literal Hola $USER.

5. ¿Por qué "$archivo_2026" no muestra el valor de archivo seguido de _2026?

Porque el guion bajo y los dígitos pueden formar parte de un nombre, y Bash lee la variable archivo_2026. Hay que delimitar el nombre con llaves: "${archivo}_2026".

6. ¿Qué se guarda en hoy con hoy="$(date +%F)", y qué pasa con el salto de línea que escribe date?

Se guarda la fecha, por ejemplo 2026-10-14. La sustitución de comandos elimina los saltos de línea del final de la salida, de modo que la variable no lo contiene.

7. ¿Qué valor queda en n después de n=5; n+=1?

51. Para una variable común, += agrega texto al final. Para sumar se usa n=$(( n + 1 )).

8. ¿Qué diferencia hay, al leerla, entre una variable vacía y una que no existe? ¿Cómo se distinguen?

Al expandirlas, ninguna: las dos dan una cadena vacía. Se distinguen con [[ -v nombre ]], que es verdadero si la variable existe aunque esté vacía. Con set -u, leer una inexistente es un error.

9. Un script define destino=/respaldos y luego ejecuta otro script. ¿Ve el segundo script la variable?

No, porque no está exportada. Solo las variables de entorno pasan a los procesos hijos. Habría que usar export destino, o pasarla solo a ese comando con destino=/respaldos otro-script.

10. ¿Por qué un script no puede cambiar el PATH de la shell desde la que lo ejecutas?

Porque el script corre en un proceso hijo, que recibe una copia del entorno. Lo que cambie en esa copia desaparece cuando el script termina. Para modificar la shell actual, el archivo debe cargarse con source.

11. ¿Qué hace LC_ALL=C sort datos.txt, y en qué se diferencia de export LC_ALL=C?

Ejecuta sort con LC_ALL=C en su entorno, solo para ese comando. export LC_ALL=C la deja en el entorno para todos los comandos que se ejecuten después.

12. Un script contiene destino="${DESTINO:-/respaldos}". ¿Cómo se ejecuta para que use /mnt/usb?

Definiendo la variable de entorno al llamarlo: DESTINO=/mnt/usb ./script. Si no se define, usa /respaldos.

13. ¿Qué ocurre si un script intenta modificar una variable declarada con readonly?

Bash muestra el error readonly variable y la variable conserva su valor. Si el script tiene set -e, se detiene ahí.

14. ¿Por qué declare -p es mejor que echo para examinar una variable?

Porque muestra el valor entre comillas, con los espacios del principio y del final, los saltos de línea y los caracteres invisibles representados como \n o \r. También muestra sus atributos, como si está exportada o es de solo lectura.

15. ¿Qué representa %% en el formato de printf?

Un signo de porcentaje literal. Un % solo marca el lugar de un dato, como en %s o %d.

Para practicar

  1. Asigna a una variable tu nombre completo y muéstrala con y sin comillas. Examínala con declare -p.
  2. Guarda en variables la fecha de hoy, el nombre del equipo y la cantidad de archivos de tu directorio personal, y muéstralas en una sola línea con printf.
  3. Prueba a=5; a+=5; echo "$a". Luego crea declare -i b=5; b+=5; echo "$b" y compara.
  4. Reproduce el experimento de la sección 9 con bash -c, antes y después de exportar la variable.
  5. Escribe un script que haga export PRUEBA=hola. Ejecútalo y luego, en la terminal, prueba echo "$PRUEBA". Cárgalo después con source y repite.
  6. Escribe un script con una variable mal escrita al leerla. Ejecútalo con y sin set -u, y pásalo por shellcheck.
  7. Agrega al final de informe-equipo una línea que muestre cuánto tardó, usando SECONDS.
  8. Instala informe-equipo en ~/bin y ejecútalo con distintos valores de UMBRAL_DISCO, mirando el código de salida con echo $?.