El shell de Linux es un intéprete de comandos que permite al administrador ejecutar determinadas tareas (leer más). Pero el shell no es únicamente eso, ya que los intérpretes de comandos son un auténtico lenguaje de programación que incorpora sentencias de control de flujo, sentencias de asignación, funciones, etc.
Los shell scripts o guiones, o simplemente scripts, son interpretados, es decir, no necesitan ser compilados, se ejecutan línea a línea. Son solamente un fichero con los comandos que necesitemos escritos en ASCII.
Cómo crear y ejecutar un script
Para crear un script solamente necesitamos un editor de texto, y comenzarlo siempre con una línea que indique el shell que se va a utilizar para ejecutar esos comandos:
#!/bin/bash
Una vez terminado editado, tendremos que otorgarle al fichero permisos de ejecución a los usuarios que puedan ejecutarlo:
chmod 755 miscript
Para ejecutar un script tenemos dos posibilidades. La primera es utilizando el intérprete de comandos (en este caso no hubiera sido necesario otorgarle permisos de ejecución):
sh miscript
La segunda es ejecutarlo directamente con su nombre y la ruta de donde se encuentra:
./miscript
Un ejemplo sencillo de script podría ser el siguiente:
#!/bin/bash clear date
Cómo depurar un script
Depurar un script consiste en ejecutarlo paso a paso para comprobar su funcionamiento o encontrar posibles errores.
Una buena idea para depurar los programas es la opción -x en la primera línea. Como consecuencia, durante la ejecución se va mostrando cada línea del script después de sustituir las variables por su valor, pero antes de ejecutarla.
#!/bin/bash -x
Otra posibilidad es utilizar la opción -v que muestra cada línea como aparece en el script (tal como está en el fichero), antes de ejecutarla:
#!/bin/bash -v
Otra opción es llamar al programa usando el ejecutable bash. Por ejemplo, si nuestro programa se llama prac1, se podría invocar como:
$ bash -x prac1 $ bash -v prac1
Ambas opciones pueden ser utilizadas de forma conjunta:
#!/bin/bash -xv
ó
$ bash -xv prac1
Recomendaciones a la hora de editar el código de un script
Una práctica ordenada permite una verificación y comprensión más cómoda y rápida, para realizar las modificaciones de forma más segura y ayudar al usuario a ejecutar el programa correctamente. Pare ello, seguir las siguientes recomendaciones:
- El código debe ser fácilmente legible, incluyendo espacios y sangrías que separen claramente los bloques de código.
- Deben añadirse comentarios claros sobre el funcionamiento general del programa principal y de las funciones, que contengan: autor, descripción, modo de uso del programa, versión y fechas de modificaciones.
- Incluir comentarios para los bloques o mandatos importantes, que requieran cierta aclaración.
- Agregar comentarios y ayudas sobre la ejecución del programa.
- Depurar el código para evitar errores, procesando correctamente los parámetros de ejecución.
- No desarrollar un código excesivamente enrevesado, ni complicado de leer, aunque esto haga ahorrar líneas de programa.
- Utilizar funciones y las estructuras de programación más adecuadas para evitar repetir código reiterativo.
- Los nombres de variables, funciones y programas deben ser descriptivos, pero no ha de confundirse con otras de ellas, ni con los mandatos internos o externos; no deben ser ni muy largos ni muy cortos.
- Todos los nombres de funciones y de programas suelen escribirse en letras minúsculas, mientras que las variables acostumbran a definirse en mayúsculas.
Caracteres especiales
Comentarios #
Con el carácter # insertaremos un comentario en el script, todo lo que venga a continuación en la misma línea sera ignorado por el intérprete.
# Esto es un comentario
Separación de comandos ;
El intérprete ejecutará como un sólo comando toda la línea hasta encontrar un salto de línea. Si queremos escribir más de un comando en una misma línea tenemos que separarlos con un punto y coma.
echo “Un comando” echo “Otro comando” echo “Un comando”; echo “Otro comando”
Cadenas de texto " " ' '
Lo que incluyamos entre comillas dobles o comillas simples será interpretado literalmente como una cadena de texto, y será presentado tal cual.
echo “Texto por pantalla” echo ‘Otro texto por pantalla’
Carácter de escape \
Una barra inclinada inversa (o invertida) no entrecomillada (\) es el carácter de escape, el cual preserva sin modificar el valor literal del siguiente carácter que lo acompaña.
echo " \" "
En el ejemplo anterior se imprimiría la comilla doble del interior, y no se confundiría con la comilla doble de cierre de cadena.
Además, según el carácter que le venga acompañado, puede significar alguno de los siguientes caracteres especiales:
- \a: alerta (campana)
- \b: espacio-atrás
- \e: carácter de escape (ESC)
- \f: nueva página
- \n: nueva línea
- \r: retorno de carro
- \t: tabulación horizontal
- \v: tabulación vertical
- \\: barra invertida
- \xnnn: carácter cuyo código es el valor hexadecimal nnn
Evaluación del contenido ` `
Lo que incluyamos entre comillas invertidas ` ` (tilde invertida) será evaluado en primer lugar, y luego el comando en el que se encuentra pero ya con el resultado del comando ejecutado en primer lugar.
echo `date`
Variables y arrays
Variables locales
Las variables locales se utilizan para poder guardar información y a partir de ella poder tomar decisiones o realizar operaciones. Las variables locales no pueden tener el nombre de ninguna palabra reservada (p.e. echo). No es necesario declarar previamente las variables, se pueden comenzar a utilizar en cualquier parte del script.
Para asignar un valor a una variable se utiliza directamente el nombre:
NUMERO=5
Para utilizar el valor de una variable se antepone el carácter $ al nombre de la variable:
echo $NUMERO
Variables de entorno
Las variables de entorno definidas en el sistema estarán a nuestra disposición en el script y podemos hacer uso de ellas para nuestros intereses (leer más).
echo $HOME
Variables de múltiples valores (Arrays)
El shell permite que se trabaje con arrays o matrices unidimensionales. Un array es una colección de elementos del mismo tipo, dotados de un nombre, y que se almacenan en posiciones contiguas de memoria. El primer subíndice del primer element del array es 0, y si no se utiliza subíndice, se considera también que se está referenciando a dicho elemento. No hay un tamaño máximo para un array, y la asignación de valores se puede hacer de forma alterna.
La sintaxis para crear e inicializar un array es la siguiente:
nombre_array=(val1 val2 val3 ...)
Para asignar un valor a un elemento concreto del array:
nombre_array[x]=valor
Para acceder a un elemento concreto del array se utiliza la siguiente sintaxis:
${nombre_array[x]}
Se pueden utilizar variables para recorrer los índices del array:
id=3
${nombre_array[$id]}
Para acceder a todos los elementos del array como si fueran todos una única palabra:
${nombre_array[*]}
Para acceder a todos los elementos del array, cada uno como si fuera una palabra independiente:
${nombre_array[@]}
Para conocer el tamaño en bytes de un elemento dado del array:
${#nombre_array[x]}
Si queremos saber el número total de elementos del array:
${#nombre_array[*]} ${#nombre_array[@]}
Reglas de evaluación de variables
Nos permite sustituir el contenido de la variable siguiendo una amplia variedad de reglas.
Regla |
Descripción |
$var |
Si está definida se devuelve su contenido, si no no se devuelve nada |
${var} |
Igual que la anterior, pero evita errores cuando se concatena con otras cadenas o variables |
${var-value} |
Si está definida se devuelve su contenido, si no se devuelve "value" |
${var=value} |
Si está definida se devuelve su contenido, si no se asigna "value" a la variable |
${var?message} |
Si está definida se devuelve su contenido, si no se envía un mensaje de error con el texto "message" |
${var+value} |
Si está definida se devuelve "value", si no se devuelve el contenido de la variable |
${var:inic:long} |
Devuelve la subcadena del contenido de la variable desde la posición "inic" y hasta completa "long" caracteres (si "long" no se especifica se devolverá hasta el final de la misma) |
${!pref*} | Devuelve los nombres de las variables que empiezan por "pref" |
${#var} | Devuelve el tamaño en caracteres del contenido de la variable |
${var#patron} ${var##patron} |
Se elimina del contenido de la variable la mínima (o la máxima) comparación del patrón, comenzando por el principio. |
${var%patron} ${var%%patron} |
Se elimina del contenido de la variable la mínima (o la máxima) comparación del patrón, comenzando por el final. |
${var/patron/cadena} ${var//patron/cadena} |
Se reemplaza en el contenido de la variable los caracteres que corresponden con el "patrón" por el valor de "cadena" (o todas las comparaciones) |
Algunos ejemplos de uso serían:
#Si no existe el primer parámetro, muestra un mensaje de error ${1?"Error: No existe el parámetro}
Parámetros de entrada y Variables internas
Al ejecutar un script podemos pasarle valores que luego podremos utilizar a nuestro antojo durante el desarrollo del mismo. Esto es lo que se conoce como parámetros de entrada del script.
Por ejemplo, podríamos ejecutar un script indicándole como primer parámetro un mes y como segundo un año.
./miscript mayo 2012
Los valores de estos parámetros lo utilizaremos en el script como variables, y siempre tendrán el mismo nombre, según la posición en la que se encuentren $1, $2... $9.
En nuestro ejemplo $1 tendrá el valor “mayo” y $2 tendrá “2012”.
Pero además tenemos otras variables que nos ayudarán a trabajar con los parámetros de entrada y otros aspectos del script:
Variable |
Descripción |
$1 $2 $3 ... $9 |
Valores de los parámetros de entrada |
$0 |
Ruta y nombre del script |
$# |
Número de parámetros de entrada |
$* |
Cadena con todos los parámetros separados por espacio en blanco |
$@ |
Cadena con todos los parámetros separados por palabras |
$$ |
Identificador del proceso (PID) |
&? |
Código de retorno del último comando (0=correcto, >0=error) |
$! |
Último identificador de proceso ejecutado en segundo plano |
$_ |
Valor del último argumento del comando ejecutado previamente |
La orden shift mueve toda la lista de parámetros de entrada una posición a la izquierda, esto hace que el contenido del parámetro $1 desaparezca, y sea reemplazado por el contenido de $2, que $2 sea reemplazado por $3, y así sucesivamente.
shift
Si ejecutamos comandos encadenados mediante tuberías (pipe), tenemos a nuestra disposición un array con el código de salida de cada uno de los comandos por separado.
Variable |
Descripción |
${PIPESTATUS[0]} |
Código de salida del primer comando encadenado |
${PIPESTATUS[1]} |
Código de salida del segundo comando encadenado |
... | |
${PIPESTATUS[*]} | Código de salida de todos los comandos encadenados |
Un ejemplo sería el siguiente, en el que queremos comprobar el código de salida del segundo comando:
ls /dev | grep a | sort echo ${PIPESTATUS[1]}
Entrada y salida de datos
Para imprimir un dato por pantalla desde el script utilizamos el comando echo, en el que podemos concatenar todas las cadenas y variables que deseemos.
echo “Valor del primer parámetro: “$1"(fin)"
Con -n no se hace el salto de línea por defecto.
echo -n `date`
Para pedir al usuario un dato desde el teclado utilizamos el comando read. El script se detendrá hasta que el usuario en la terminal introduzca un valor con el teclado. Este valor se introducirá en la variable indicada a continuación del comando (sin el carácter $), y podremos trabajar con él como con cualquier otra variable.
read numero1 read numero1,numero2,numero3
Con -p incluimos una cadena de caracteres al pedirle el dato al usuario:
read -p "Introduce un número" numero1
Nos puede servir también como un pause si no incluimos ninguna variable:
read -p "Pulsa una tecla para continuar..."
Expresiones
Expresiones aritméticas
El shell permite que se evalúen expresiones aritméticas, bajo ciertas circunstancias. La evaluación se hace con enteros largos sin comprobación de desbordamiento, aunque la división por 0 se atrapa y se señala como un error. La lista siguiente de operadores se agrupa en niveles de operadores de igual precedencia, se listan en orden de precedencia decreciente.
-, + | Menos y más unarios |
~ | Negación lógica y de bits |
** | Exponenciación |
*, /,% | Multiplicación, división, resto |
+, - | Adición, sustracción |
<<, >> | Desplazamientos de bits a izquierda y derecha |
<=, >= , <, > | Comparación |
==, != | Igualdad y desigualdad |
& | Y de bits (AND) |
^ | O exclusivo de bits (XOR) |
| | O inclusivo de bits (OR) |
&& | Y lógico (AND) |
|| | O lógico (OR) |
expre?expre:expre | Evaluación condicional |
=, +=, -=, *=, /=,%=, &=, ^=, |= <<=, >>= | Asignación: simple, después de la suma, de la resta, de la multiplicación, de la división, del resto,del AND bit a bit, del XOR bit a bit, del OR bit a bit, del desplazamiento a la izquierda bit a bit y del desplazamiento a la derecha bit a bit. |
Los operadores se evalúan en orden de precedencia. Las subexpresiones entre paréntesis se evalúan primero y pueden sustituir a las reglas de precedencia anteriores.
Existen tres maneras de realizar operaciones aritméticas:
1. Con let lista_expresiones, como se ha dicho anteriormente, se pueden evaluar las expresiones aritméticas dadas como argumentos. Es interesante destacar que esta orden no es estándar, sino que es específica del bash. A continuación se muestra un ejemplo de su uso:
let a=6+7 echo El resultado de la suma es $a $ El resultado de la suma es: 13 let b=7%5 echo El resto de la división es: $b $El resto de la división es: 2 let c=2#101\|2#10 echo El valor de c es $c $ El valor de c es 7
2. La orden expr sirve para evaluar expresiones aritméticas. Puede incluir los siguientes operadores: \(, \), \*, \\, \+, \-, donde el carácter ’\’ se introduce para quitar el significado especial que pueda tener el carácter siguiente. Por ejemplo:
expr 10 \* \( 5 \+ 2 \) i=‘expr $i - 1‘ #restará 1 a la variable i
3. Mediante $(( expresión )) también se pueden evaluar expresiones. Varios ejemplos de su uso serían:
echo El resultado de la suma es $((6+7)) $ El resultado de la suma es: 13 echo El resto de la división es: $((7%5)) $ El resto de la división es: 2 echo El valor es $((2#101|2#10)) $ El valor de c es 7
Expresiones condicionales
Las expresiones condicionales nos permiten evaluar si una expresión es verdadera o falsa. No sólo operan sobre los valores de las variables, también permiten conocer, por ejemplo, las propiedades de un fichero.
Para ello, tenemos dos sintaxis diferentes:
test expresión [ expresión ]
¡OJO! Los espacios en blanco entre la expresión y los corchetes son obligatorios.
Para números:
-eq | Igual a |
-ne | Distinto de |
-lt | Menor que |
-le | Menor o igual que |
-gt | Mayor que |
-ge | Mayor o igual que |
Es importante destacar que en las comparaciones con números si utilizamos una variable y no está definida, saldrá un mensaje de error.
[ $e -eq 1 ] [ ${e=0} -eq 1 ]
Para caracteres alfabéticos o cadenas:
-z cadena | Verdad si la longitud de cadena es cero |
-n cadena | Verdad si la longitud de cadena no es cero |
cadena1 == cadena2 | Verdad si las cadenas son iguales. Se puede emplear =en vez de == |
cadena1 != cadena2 | Verdad si las cadenas no son iguales |
cadena1 < cadena2 | Verdad si cadena1 se ordena lexicográficamente antesde cadena2 en la localización en curso |
cadena1 > cadena2 | Verdad si cadena1 se clasifica lexicográficamente despuésde cadena2 en la localización en curso |
Para operaciones con ficheros:
-e fichero | El fichero existe |
-r fichero | El fichero existe y tengo permiso de lectura |
-w fichero | El fichero existe y tengo permiso de escritura |
-x fichero | El fichero existe y tengo permiso de ejecución |
-f fichero | El fichero existe y es regular |
-s fichero | El fichero existe y es de tamaño mayor a cero |
-d fichero | El fichero existe y es un directorio |
-L fichero | El fichero existe y es un enlace simbólico |
Además se pueden incluir operadores lógicos y paréntesis:
-o | OR |
-a | AND |
! | NOT |
\( | Paréntesis izquierdo |
\) | Paréntesis derecho |
Algunos ejemplos serían:
test $# -ne 2 test -f "$1" test -d "$1" [ $S1!=$S2 ]
Listas de órdenes y grupos de órdenes
Carácter ; o salto de línea
Nos permite separar una orden de otra. El punto y coma nos permite además incluir más de una orden en la misma línea.
ls $HOME; pwd
Carácter \
Permite escribir una misma orden en más de una línea, normalmente cuando son muy largos.
mdadm --create /dev/md0 --metadata=0.90 \ --level=1 --raid-devices=2 /dev/sdb1 /dev/sdc1
Carácter &
Ejecuta un comando en segundo plano y sigue con la ejecución del siguiente (leer más).
cp -axv / /mnt/disco2 &
orden1 && orden2
Nos permite simular una operación Y (AND). orden2 se ejecuta si y sólo si orden1 devuelve un código de error 0.
test -e leeme.txt && echo "El fichero leeme.txt sí existe"
orden1 || orden2
Nos permite simular una operación O (OR). orden2 se ejecuta si y sólo si orden1 devuelve un código de error distinto a 0.
test -e leeme.txt || echo "El fichero leeme.txt no existe"
{ orden1; orden2; ... ordenx; }
Todas las órdenes se ejecutan simplemente en el mismo entorno shell (terminal), sin crear un shell nuevo. Se conoce como orden de grupo.
{ cd bin; ls; } { echo a; echo b; } | sort
( orden1; orden2; ... ordenx; )
Todas las órdenes se ejecutan en un shell nuevo, diferente al que se lanzan las órdenes, se hace un fork (hijo).
( cd bin; ls; ) ( echo a; echo b; ) | sort
Estructuras de control
NOTA: Las palabras reservadas then, in, do... para ir en la misma línea que la palabra reservada del bucle deben estar precedidas de un punto y coma que los separe de la condición o las variables.
Condicional simple (if)
Nos permite bifurcar la ejecución del script en caso de que la condición sea verdadera o falsa.
if expresión then comandos1 else comandos2 fi
if expresión ; then comandos1 else comandos2 fi
if expresión1 then comandos1 elif expresión2 comandos2 fi
A continuación mostramos un ejemplo:
if [ "$HOME" == "/root" ] then echo "Eres el usuario ROOT" else echo "Eres un usuario normal" fi
Condicional múltiple (case)
Nos permite bifurcar la ejecución del script en función del valor de una variable. Se ejecutarán los comandos que existan desde la línea que posea el mismo valor que el almacenado en la variable hasta encontrar el siguiente valor. Podemos separar diferentes comandos al situarlos en líneas diferentes o con puntos y coma, teniendo en cuenta que siempre el último comando estará seguido de dos puntos y comas.
También podemos escribir varios valores separados por el carácter |. La opción * se ejecutará cuando el valor no coincida con ninguno de los expresados.
Las cadenas las podemos expresar con comillas o sin comillas, menos cuando contenga espacios en blanco, donde sí tendremos siempre que utilizar comillas.
case $variable in valor1) instrucción1; instrucción2;; valor2 | valor3) instrucción4; instrucción5;; *) intrucción_por_defecto;; esac
Un ejemplo sería:
read ELECCION case $ELECCION in a|A) programa1 programa2 programa3 ;; b|B) programa4 programa5 ;; c|C) programa3 ;; *) echo "No eligió ninguna opción válida" ;; esac
Bucle condicional mientras (while)
Los comandos incluidos en el interior del bucle se ejecutarán indefinidamente mientras las condiciones sean verdaderas. La sintaxis es:
while condicion do instrucción1 instrucción2 ... done
Un ejemplo:
opcion=1 while [ $opcion -ge 1 ] && [ $opcion -le 3 ] do clear echo "Menu" echo "1) Opcion 1." echo "2) Opcion 2." echo "3) Opcion 3." echo "4) Salir." echo "Introduzca una opcion: " read opcion case $opcion in 1) echo "Ejecutando 1." echo "Espere" sleep 2;; 2) echo "Ejecutando 2." echo "Espere" sleep 2;; 3) echo "Ejecutando 3." echo "Espere" sleep 2;; 4 | 0) echo "Saliendo.";; *) echo "Ejecutando no valido.";; echo "Espere" sleep 2;; esac done
Bucle condicional hasta (until)
Los comandos incluidos en el interior del bucle se ejecutarán indefinidamente hasta que las condiciones sean verdaderas. La sintaxis es:
until condicion do instrucción1 instrucción2 ... done
Un ejemplo:
opcion=1 until [ $opcion -eq 4 ] || [ $opcion -eq 0 ] do clear echo "Menu" echo "1) Opcion 1." echo "2) Opcion 2." echo "3) Opcion 3." echo "4) Salir." echo "Introduzca una opcion: " read opcion case $opcion in 1) echo "Ejecutando 1." echo "Espere" sleep 2;; 2) echo "Ejecutando 2." echo "Espere" sleep 2;; 3) echo "Ejecutando 3." echo "Espere" sleep 2;; 4 | 0) echo "Saliendo.";; *) echo "Ejecutando no valido.";; echo "Espere" sleep 2;; esac done
Bucle repetitivo para (for)
Los comandos incluidos en el interior del bucle se ejecutarán una vez por cada uno de los valores incluidos en la lista. Para crear una lista numérica podemos utilizar el comando seq.
for variable in lista do instrucción1 instrucción2 ... done
Una serie de ejemplos de utilización serían:
for numero in 1 2 3 4 5 6 do echo $numero done
for numero in `seq 1 6` do echo $numero done
for www in www.google.com www.cisco.com do echo $www done
Ruptura de bucles: break y continue
Las órdenes break y continue sirven para interrumpir la ejecución secuencial del cuerpo de un bucle. La orden break transfiere el control a la orden que sigue a done, haciendo que el bucle termine antes de tiempo. La orden continue, por el contrario, transfiere el control a done, haciendo que se evalúe de nuevo la condición, es decir, la ejecución del bucle continúa en la siguiente iteración. En ambos casos, las órdenes del cuerpo del bucle siguientes a estas sentencias no se ejecutan. Lo normal es que formen parte de una sentencia condicional.
Un par de ejemplos de su uso serían:
# Muestra todos los parámetros, si encuentra una "f" finaliza while [ $# -gt 0 ] do if [ $1 = "f" ] then break fi echo Parámetro: $1 shift done # Muestra todos los parámetros, si encuentra una "f" # se lo salta y continúa el bucle while [ $# -gt 0 ] do if [ $1 = "f" ] then shift continue fi echo Parámetro: $1 shift done
Soluciones a problemas típicos
Comprobación de cadena vacía
La cadena vacía a veces da algún problema al tratar con ella. Por ejemplo, considérese el siguiente trozo de código:
if [ $a = "" ] ; then echo "cadena vacia" ; fi
¿Qué pasa si la variable a es vacía? pues que la orden se convierte en:
if [ = "" ] ; then echo "cadena vacia" ; fi
Lo cual no es sintácticamente correcto (falta un operador a la izquierda de “=”). La solución es utilizar comillas dobles para rodear la variable:
if [ "$a" = "" ] ; then echo "cadena vacia" ; fi
o incluso mejor, utilizar la construcción:
if [ "x$a" = x ] ;then echo "cadena vacia" ; fi
La “x” inicial impide que el valor de la variable se pudiera tomar como una opción.
Leer un fichero línea a línea
A veces surge la necesidad de leer y procesar un fichero línea a línea. La mayoría de las utilidades de UNIX tratan con el fichero como un todo, y aunque permiten separar un conjunto de líneas, no permiten actuar una a una. La orden read ya se vió para leer desde el teclado variables, pero gracias a la redirección se puede utilizar para leer un fichero.
while read i ; do echo "Línea: $i" ... done < $fichero
El bucle termina cuando la función read llega al final del fichero de forma automática.
Leer argumentos opcionales de la línea de comandos
Aunque puede hacerse mediante programación “convencional”, el bash ofrece una alternativa interesante para esta tarea. Se trata de la orden getopts. La mejor manera de ver cómo se utiliza es con un ejemplo:
while getopts t:r:m MYOPTION; do case $MYOPTION in t) echo "El argumento para la opción -t es $OPTARG" ;; r) echo "El índice siguiente al argumento de -r es $OPTIND" ;; m) echo "El flag -m ha sido activado" ;; ?) echo "Lo siento, se ha intentado una opción no existente"; exit 1; ;; esac done
Podemos ahora probar el efecto de una invocación del guión como ésta:
./script -m -r hola -t adios -l
La salida sería la siguiente:
El flag -m ha sido activado El índice siguiente al argumento de -r es 4 El argumento para la opción -t es adios ./guion: opción ilegal -- l Lo siento, se ha intentado una opción no existente
El mensaje de la cuarta línea es en realidad enviado a la salida estándar de error, por lo que si se quisiera se podría eliminar redireccionando con 2> a /dev/null.
Como puede observarse, getopts comprueba si las opciones utilizadas están en la lista permitida o no, y si han sido llamadas con un argumento adicional (indicado por los :) en la cadena de entrada “t:r:m”. Las variables $MYOPTION, $OPTIND y $OPTARG contienen en cada paso del bucle, respectivamente, el carácter con la opción reconocida, el lugar que ocupa el siguiente argumento a procesar, y el parámetro correspondiente a la opción reconocida (si ésta iba seguida de : en la cadena de entrada.