Programación Shell-2021
Programación Shell-2021
Laboratorio de Herramientas
Computacionales
Prof. Heriberto Quezada Moreno
FIE
INTRODUCCIÓN
🞆 El intérprete de comandos o "shell" de UNIX
es también un lenguaje de programación
completo. La programación de shell se usa
mucho para realizar tareas repetidas con
frecuencia.
🞆 El shell de UNIX tiene un excelente
rendimiento en la ejecución de "scripts"
(guiones)
COMANDOS MULTILÍNEA
🞆 Una línea de comando termina con un
carácter nueva línea. El carácter nueva línea
se ingresa digitando la tecla ENTER. Varios
comandos pueden escribirse en una misma
línea usando el separador ";"
echo $LOGNAME; pwd; date
🞆 Si un comando no cabe en una línea, la
mayoría de los intérpretes continúan la
digitación en la línea siguiente. Para
establecer específicamente que un comando
continúa en la línea siguiente, hay dos
formas, mutuamente excluyentes (se usa
una u otra, pero no ambas al mismo tiempo):
🞆 - terminar la primera línea con \ :
$ echo $LOGNAME \
> $HOME
que muestra algo como
jperez /home/jperez
🞆 - dejar una comilla sin cerrar:
$ echo "$LOGNAME
> $HOME"
que produce el mismo resultado.
🞆 En los ejemplos anteriores hemos escrito los
indicadores de comando. Al continuar el
comando en la segunda línea, el indicador de
comandos cambia de $ a >, es decir, del
indicador de comando de primer nivel PS1 al
indicador de comando de segundo nivel PS2.
Si no se quiere terminar el comando
multilínea, puede interrumpirse el ingreso
con Ctrl-C, volviendo el indicador de
comando a PS1 inmediatamente.
EL ARCHIVO DE COMANDOS
(SCRIPT).
🞆 MATRICULASHELL230531
desde i = 1 hasta i = 7
escribir dia_semana(i);
🞆 Esta escritura informal se denomina
"pseudocódigo", por contraposición al
término "código", que sería la escritura
formal en un lenguaje de programación.
🞆 En el segundo ejemplo, dia_semana(i) sería
una función que devuelve el nombre del día
de la semana cuando se le da su número
ordinal.
ESTRUCTURA ALTERNATIVA:
🞆 en base a la comprobación de una condición,
se decide una acción diferente para cada
caso.
función dia_semana(día_hoy)
caso $dia_hoy en
1)
devolver "Lunes";;
2)
devolver "Martes";;
3)
devolver "Miércoles";:
4)
devolver "Jueves";;
5)
devolver "Viernes;;
6)
devolver "Sábado";;
7)
devolver "Domingo";;
fin caso;
COMANDOS DE PROGRAMACIÓN.
🞆 En esta sección veremos los comandos
típicos de programación del shell. Obsérvese
que el shell toma la convención inversa de C
para cierto y falso: cierto es 0, y falso es
distinto de 0. El shell adopta esta convención
porque los comandos retornan 0 cuando no
hubo error. Veremos dos
comandos, true y false, que retornan siempre
estos valores; se usan en algunas situaciones
de programación para fijar una condición.
TRUE
🞆 Este comando no hace nada, sólo devuelve
siempre 0, el valor verdadero. La ejecución
correcta de un comando cualquiera devuelve
0.
true
echo $?
muestra el valor 0; la variable $? retiene el
valor de retorno del último comando
ejecutado.
FALSE
🞆 Este comando tampoco hace nada sólo
devuelve siempre 1; cualquier valor diferente
de 0 se toma como falso. Las diversas
condiciones de error de ejecución de los
comandos devuelven valores diferentes de 0;
su significado es propio de cada comando.
false
echo $?
muestra el valor 1.
IF
🞆 El comando if implementa una estructura
alternativa. Su sintaxis es
if expresión ; then comandos1 ; [else comandos2 ;] fi
🞆 o también
if expresión
then
comandos1
[else
comandos2]
fi
SI CONDICIÓN ES CIERTA
ENTONCES
COMANDO1
COMANDO2
…
SI NO
COMANDOM
COMANDOM+1
…
FIN DE BLOQUE
if expresión1 then
comando1
…
[elif expresión2 then
comandoM
…
[elif expresión3 then
comandoN
…
…
[else
comandoZ
comandoZ+1
…]]]
fi
ARCHIVO 3
Nombre del archivo: matricula_trabajo.sh
#!/bin/bash
# trabajo.sh: dice si se trabaja según el día
# invocar con parámetros:
# domingo, feriado, u otro nombre cualquiera
#
if [ $1 = "domingo" ]
then
echo "no se trabaja"
elif [ $1 = "feriado" ]
then
echo "en algunos se trabaja"
else
echo "se trabaja"
fi
FOR
🞆 Este comando
implementa una
estructura repetitiva, en
la cual una secuencia
de comandos se ejecuta
una y otra vez.
🞆 Su sintaxis es:
for variable in lista ;
do comandos ; done
SE PUEDE PROBAR EN LA LÍNEA DE
COMANDOS:
for NUMERO in 1 2 3 4 ; do echo $NUMERO ;
done
for NOMBRE in alfa beta gamma ; do echo
$NOMBRE ; done
for ARCH in * ; do echo Nombre archivo
$ARCH ; done
El caracter * es expandido por el shell
colocando en su lugar todos los nombres de
archivo del directorio actual.
ARCHIVO 4
Nombre del archivo: matricula_listapal.sh
#!/bin/bash
# matricula_listapal.sh: lista de palabras
# muestra palabras de una lista interna
#
LISTA="silla mesa banco cuadro armario"
for I in $LISTA
do
echo $I
done
# fin listapal.sh
ARCHIVO 5
Nombre del archivo: matricula_contar.sh
#!/bin/bash
# matricula_contarch.sh
# muestra nombres y cuenta archivos en el
#directorio actual
#
CUENTA=0 #inicialización de variable con valor inicial =
0
for ARCH in *
do
echo $ARCH
CUENTA=`expr $CUENTA + 1` # agrega 1 a CUENTA
done
echo Hay $CUENTA archivos en el directorio `pwd`
# fin contarch.sh
CASE
🞆 Este comando implementa alternativas o "casos"; elige
entre múltiples secuencias de comandos la secuencia a
ejecutar. La elección se realiza encontrando el primer
patrón con el que aparea una cadena de caracteres.
case $CADENA in
patrón1)
comandos1;;
patrón2)
comandos2;;
...
*)
comandosN;;
esac
SINTAXIS CASE
case $CADENA in
patrón1)
comandos1;;
patrón2)
comandos2;;
...
*)
comandosN;;
esac
🞆 El patrón * se coloca al final; aparea
cualquier cadena, y permite
ejecutar comandosN cuando ninguna de las
opciones anteriores fue satisfecha.
ARCHIVO 6
Nombre del archivo: matricula_diasemana.sh
#!/bin/bash
# diasemana.sh: nombres de los días de la semana
# invocar con número del 0 al 6; 0 es domingo
case $1 in
0) echo Domingo;;
1) echo Lunes;;
2) echo Martes;;
3) echo Miércoles;;
4) echo Jueves;;
5) echo Viernes;;
6) echo Sábado;;
*) echo Debe indicar un número de 0 a 6;;
esac
🞆 Invocarlo como
diasemana.sh N
donde N es cualquier número de 0 a 6, otro
número, o una cadena cualquiera. Verificar el
comportamiento.
ARCHIVO 7
Nombre del archivo: matricula_estacion.sh
#!/bin/bash
# matricula_estacion.sh
# indica la estación del año aproximada según el mes
#
case $1 in
diciembre|enero|febrero)
echo Verano;;
marzo|abril|mayo)
echo Otoño;;
junio|julio|agosto)
echo Invierno;;
setiembre|octubre |noviembre)
echo Primavera;;
*)
echo estacion.sh: debe invocarse como
echo estacion.sh mes
echo con el nombre del mes en minúscula;;
esac
# fin estacion.sh
🞆 El valor $1 es el parámetro recibido en la
línea de comando. La opción *) aparea con
cualquier cadena, por lo que actúa como "en
otro caso"; es útil para dar instrucciones
sobre el uso del comando. En las opciones, |
actúa como OR; pueden usarse también
comodines * y ?. Invocar el script:
bash estacion.sh octubre
bash estacion.sh
🞆 ¿Cómo podría modificarse el script anterior
para que aceptara el mes en cualquier
combinación de mayúsculas y minúsculas?
WHILE
🞆 Este comando implementa una estruc-
tura repetitiva en la cual el conjunto
de comandos se ejecuta mientras se
mantenga válida una condición
(while = mientras). La condición se
examina al principio y luego cada vez
que se completa la secuencia de
comandos. Si la condición es falsa desde la primera
vez, los comandos no se ejecutan nunca. Su sintaxis
es
while condición ; do comandos ; done
🞆 En el guión que sigue la expresión entre
paréntesis rectos es una forma de invocar el
comando test, que realiza una prueba
devolviendo cierto o falso. El operador -lt,
"lower than", significa "menor que". Observar
su sintaxis, sobre todo la posición de los
espacios en blanco, obligatorios.
ARCHIVO 8
Nombre del archivo: matricula_crear1.sh
#!/bin/bash
# matricula_crear1.sh
# crea archivos arch1....arch9, los lista y luego borra
VAL=1
while [ $VAL -lt 10 ] # mientras $VAL < 10
do
echo creando archivo arch$VAL
touch arch$VAL
VAL=`expr $VAL + 1`
done
ls -l arch[0-9]
rm arch[0-9]
# fin crear1.sh
UNTIL
🞆 Este comando implementa una estructura
repetitiva en la cual el conjunto de comando se
ejecuta hasta que se cumpla una condición. En
cuanto la condición se cumple, dejan de
ejecutarse los comandos. La condición se examina
al principio; si es verdadera, los comandos no se
ejecutan. Notar la diferencia con while. Su sintaxis
es
until condición ; do comandos ; done
ARCHIVO 9
USANDO UNTIL, EL SCRIPT ANTERIOR SE ESCRIBIRÍA:
#!/bin/bash
# matricula_ecopars.sh
# muestra los parámetros recibidos
echo Cantidad de parámetros: $#
for VAR in $*
do
echo $VAR
done
# fin matricula_ecopars.sh
🞆 ecopars.sh Enero Febrero Marzo
muestra la cantidad y los parámetros
recibidos. La variable $* contiene la lista de
parámetros, y $# la cantidad.
🞆 Dentro del script, los parámetros recibidos
pueden referenciarse con $1, $2, $3, ..., $9,
siendo $0 el nombre del propio programa.
Debido a que se los reconoce por su
ubicación, se llaman parámetros
posicionales.
ARCHIVO 15
EL SIGUIENTE PROGRAMA SE INVOCA CON
TRES PARÁMETROS Y MUESTRA SUS VALORES:
#!/bin/bash
# matricula_mostrar3.sh
# se invoca con 3 parámetros y los muestra
echo nombre del programa: $0
echo parámetros recibidos:
echo $1; echo $2; echo $3
echo
# fin matricula_mostrar3.sh
🞆 ¿Cómo se podría verificar la invocación con 3
parámetros, y emitir un mensaje de error en
caso contrario (cuando el usuario ingresa
menos de 3 parámetros)?
DEPURACIÓN.
🞆 Se llama depuración ("debug") de un
programa al proceso de verificar su
funcionamiento en todos los casos posibles y
corregir sus errores ("bugs", "pulgas"; del
inglés, literalmente, "chinche"; por extensión,
insecto pequeño).
🞆 Cuando se está escribiendo un script, puede
convenir invocarlo de forma especial para
generar información de comandos
ejecutados y errores, para ayudar en la
depuración. Las salidas se imprimen en el
error estándar, por lo que pueden
direccionarse a un archivo sin mezclarse con
la salida del comando.
🞆 bash -x ecopars.sh
imprime cada comando en la salida;
bash -v ecopars.sh
invoca el script obteniendo una salida
verbosa con información sobre cada
comando ejecutado.
bash -xv ecopars.sh 2>ecopars.err
reúne las dos fuentes de información y
direcciona el error estándar a un archivo.