Nanocurso de Shell Script

Este es mi Nanocurso de lenguaje de Shell Script, a petición del distinguido público. Como ya es tradicional, alguien preguntará por la versión en inglés. Que vaya a mi Journal de AOL, cuya URL es sobradamente conocida para el que lo quiere en inglés. De nada.

Extra ball: Que lo ponga en línea, que el PDF no se lee bien. Vale, a su servicio. Pero tendrá que esperar al fin de semana.

Update ball: Hecho. Helo acá.

Shell Script Paso a Paso

Índice

1. Variables
2. Matrices
3. Fechas
4. Decisión simple y múltiple
5. Bucle FOR
6. Bucle WHILE, y nueva visita a las matrices

1. Variables

Concepto: Área de memoria definida por el programa, alberga un VALOR que puede cambiarse en cualquier momento de la ejecución del mismo. Se hace referencia a ella mediante su NOMBRE. En algunos lenguajes las variables tienen TIPO, que es una limitación del ontenido admitido (solamente números enteros, cadenas alfanuméricas, valores de coma flotante, etc.)

Implementación: Se define la variable con la sintaxis nombre=valor y se hace referencia a ella empleando $nombre en el código.

Muy al estilo de cualquier otro lenguaje de programación por procedimientos, aunque por convenio se escriben con mayúsculas los nombres de las variables… lo odio, y paso de hacerlo…

Cuando aparecen caracteres “raros” en los nombres de las variables, o se puede roducir una confusión, se encierra el nombre entre llaves:

set -x
base=34
altura=7
area=`expr $base * $altura / 2`
echo "El área del triángulo de base $base y altura $altura es: $area"
nombre="Claudia"
echo "El nombre de la modelo es ${nombre}"

Otro ejemplo: Se dispone de unos ficheros cuyos nombres siguen el formato “mes seguido del número 777″. Si no se ponen las llaves (codificando, por ejemplo, nombrefichero=$mes777) se produce una confusión:

El intérprete busca la variable $mes777, que no existe. La solución es:

mes="febrero"
nombrefichero=${mes}777
echo "Copiando ${nombrefichero}..."
$mes="febrero"
$nombrefichero=$mes777

2. Matrices

Concepto: Variable con múltiples valores. Se accede a cada valor individual mediante un índice numérico.

Implementación: Nombre seguido del índice encerrado entre corchetes. Se define cada valor con la sintaxis nombre[$indice]=valor y se hace referencia a ella empleando $nombre[$indice] en el código:

vecino[1]="el vecino del primero"
vecino[2]="la maciza del segundo"
vecino[3]="la vieja del tercero"
piso=1
echo "En el piso ${piso} vive ${vecino[ $piso ]}"
Como puede verse, esto lo entiende cualquier hijo de vecino.

3. Fechas

Concepto: Obtener la fecha del sistema en varios formatos, de modo que sea posible usarla en el resto del script.

Implementación: Invocar el mandato date con los parámetros adecuados. Sin pretender ser exhaustivo, he aquí unos cuantos usos útiles:

# Week day: mon tue wed ...
diasemana=`date +%a`
echo "El día de la semana es: $diasemana"
# day/month/year
diamesano=`date +%d/%m/%Y`
echo "En formato 'día/mes/año', hoy es... $diamesano"
# hour minute second
horminseg=`date +%H %M %S`
echo "En formato 'hora minuto segundo', son las $horminseg"
# week day: 1 for monday, 2 for tuesday...
numdiasem=`date +%u`
echo "Día de la semana (1=lunes, 2=martes...), hoy es $numdiasem"
# week number thru the year
numsemano=`date +%V`
echo "Número de semana en el año (01 a 53)”
echo “esta es la semana $numsemano"
# Julian date: January 1 is number 1
diajuliano=`date +%j`
echo "Fecha Juliana: $diajuliano"
echo "Teclee ‘man date’ para mostrar todos los formatos"

4. Decisión simple y múltiple

Concepto: Ejecución condicional de código en función del cumplimiento o incumplimiento de una condición.

Implementación: La estructura de decisión tiene la sintaxis if [ condicion ]; then instrucciones; else instrucciones tal y como se muestra en este ejemplo:

read -p "Piensa otro número: " respuesta
echo "Esta es tu respuesta al enigma: $respuesta"

REPLY es una variable del intérprete, que toma el valor de la respuesta proporcionada por el usuario al ejecutarse la instrucción read. Una alternativa a la construcción anterior es:

read -p "Piensa un número, escríbelo aquí y pulsa ENTER. "
if [ "$REPLY" -eq "34" ]
then
echo "Has adivinado mi número secreto."
echo "Es el treinta y cuatro."
else
echo "Lo siento."
echo "Prueba otro día."
fi

En CASE se refleja el concepto de la instrucción SWITCH del lenguaje C y de la sentencia EVALUATE de COBOL II, pero de manera simplificada. No olvide poner los dos “puntos y coma” para evitar que se siga ejecutando hacia abajo al entrar en un CASE.

speed=120
case $speed in
0)
  echo "Estás parado."
  ;;
90)
  echo "Vas dentro de los límites de carretera normal."
  ;;
120)
  echo "Vas en el límite de autopista."
  ;;
130)
  echo "Esa multa..."
  ;;
*)
  echo “Esta velocidad no me suena.”
  # None of the above, this speed is unfamiliar to me
esac

5. Bucle FOR

Concepto: Ejecución repetida de una o varias instrucciones, habitualmente cambiando el valor de una variable a cada vuelta del bucle.
Implementación: El conocido bucle FOR se reedita en bash de esta manera:

for (( i = 0; i '<' 10; i ++ ))
do
  echo "Vuelta número $i"
done

La siguiente versión del bucle FOR recorre una lista. Por defecto, la separación entre palabras de la lista se realiza entre espacios. Para separar por líneas se modifica la variable IFS (Input Field Separator), dándole el valor “nueva línea” (mediante la secuencia de teclas [Control-M], o sea, mantenga pulsada [Control] y pulse M. Después, suéltelo todo)

IFS="^M"
nombre="Claudia"
apellidos="Schiffer Gliffer"
telefono="1-800-MASQUISIERAS"
for i in $nombre $apellidos $telefono
do
  echo $i
done

La salida de la ejecución de una orden puede usarse como lista empleando las comillas “inclinadas”.

IFS="^M"
i=1
for n in `ls -1`
do
  echo "El fichero $i se llama $n"
  i=`expr $i + 1`
done

6. Bucle WHILE, y nueva visita a las matrices

Se puede visitar de nuevo el ejemplo de las matrices, usando el contador del bucle para acceder a la matriz. Cada vuelta del bucle procesa un elemento de la matriz.

vecino[1]="el vecino del primero"
vecino[2]="la maciza del segundo"
vecino[3]="la vieja del tercero"
for i in 1 2 3
do
  echo "En el piso $i vive ${vecino[ $i ]}"
done

Este es el bucle típico de COBOL -tal y como se codificaba en los setenta y ochenta usado para procesar un fichero secuencial. Cada vuelta del bucle manejaba un registro (una línea) del fichero. Se iniciaba el proceso con una primera lectura antes de entrar en el bucle:

Lectura
Repetir hasta que se acaben los datos
Proceso del dato leído anteriormente
Lectura
Final del bucle “Repetir”

COBOL no disponía, en sus primeras versiones, de instrucciones para salir del bucle en el centro del mismo o para comprobar la condición “hasta que…” en cualquier punto distinto del principio. Era necesario, por tanto, codificar de este modo. En shell script se construye así:

loop=1
read -s
rc=$?
while [ $rc -eq 0 ] do
  echo "Estamos en la vuelta ${loop}: '${REPLY}'"
  read -s
  rc=$?
  loop=`expr ${loop} + 1`
done
echo "Final del proceso. En total, ${loop} vueltas."

La variable $? contiene el valor de retorno del último mandato ejecutado. Se simplifica mucho el código por el hecho de disponer de una manera de abandonar el bucle en cualquier punto del mismo:

loop=1
while [ /bin/true ]
do
  read -s || break
  echo "Estamos en la vuelta ${loop}: '${REPLY}'"
  loop=`expr ${loop}+ 1`
done
echo "Final del proceso. En total, ${loop} vueltas."

Otra versión, con el uso de IF para comprobar los datos recibidos:

loop=1
while [ /bin/true ]
do
  read -s
  if [ $? -gt 0 -a -z "${REPLY}" ]; then break; fi
  echo "'${REPLY}' in loop ${loop}"
  loop=`expr ${loop} + 1`
done

Se usa “-a” como AND lógico entre dos condiciones, y “-z” para comprobar si unacadena de caracteres tiene longitud cero.

2 comments on “Nanocurso de Shell Script

Deja un comentario

Fill in your details below or click an icon to log in:

Logo de WordPress.com

You are commenting using your WordPress.com account. Log Out / Cambiar )

Twitter picture

You are commenting using your Twitter account. Log Out / Cambiar )

Facebook photo

You are commenting using your Facebook account. Log Out / Cambiar )

Connecting to %s