Las historias de Zenon

  • RSS Alguien no quiere que leamos esto

    • Se ha producido un error; es probable que la fuente esté fuera de servicio. Vuelve a intentarlo más tarde.
  • Historial

    noviembre 2007
    L M X J V S D
     1234
    567891011
    12131415161718
    19202122232425
    2627282930  
  • Mis enlaces en del.icio.us

  • Meta

  • Pobreza cero

  • Cultura Libre

    Cultura Libre
  • Linux Counter


    The Ubuntu Counter Project - user number # 3747
  • Licencia

    El contenido de esta bitácora se encuentra protegido bajo la licencia Reconocimiento - CompartirIgual de Creative Commons.
    Reconocimiento y Compartir igual

    © Jose Luis Jimenez, Getafe 2006
    Los comentarios son responsabilidad exclusiva de los autores de los mismos.

Aventurandose por los shell scripts II

Posted by Jose Luis en 29 noviembre 2007

Hace varios meses escribí una pequeña introducción sobre los shell-scripts utilizando bash como shell, y se me quedaron un montón de cosas en el tintero.
Algunas de las cosas de las que no hablé fueron la utilización de arrays en un script de bash (es importante el uso de bash porque en otras shell como ksh o csh no están implementados los arrays), la lectura de un fichero desde un script, y cómo recoger parámetros en un script sin conocer el orden.

Antes de nada decir que lo que voy a contar aquí no es para nada riguroso por lo que los puristas de la informática que no me tomen muy en serio.

¿Qué es un array?
Si recurrimos a la wikipedia, y hablando en términos de programación informática, tenemos que un array o vector, arreglo o alineación es un conjunto o agrupación de variables del mismo tipo cuyo acceso se realiza por índices.

En cierta forma un array es como un armario con muchos cajones (en bash son ilimitados) en los que podemos guardar cosas. Así si consideramos que el primer cajón es el de abajo y hemos guardado ahí los calcetines, en el segundo las camisetas blancas, en el tercero las camisetas de otro color y en el cuarto los calzoncillos (o bragas o lo que corresponda), para decir donde se encuentran las camisetas blancas es suficiente con decir que están en el segundo cajón del armario. Si hubiera más de un armario tendriamos que nombrarlos de alguna forma, el armario de la habitación grande, el armario del pasillo, …

Pues un array es algo parecido, tiene un nombre para saber a qué armario nos estamos refiriendo, y tienen elementos (cajones) en los que guardar lo que queramos. Además, en bash los elementos o cajones se empiezan a numerar desde 0, es decir el primero es el elemento 0, el segundo el 1, el tercero el 2, … Cada uno de esos números que referencia un elemento del array es lo que se llama el índice (de alguna forma indica donde está el cajón)

¿Cómo llenamos nuestro armario?
Cuando queremos guardar algo en un cajón lo que tenemos que hacer es asignar ese algo al elemento correspondiente del array.
En bash esto se hace de la siguiente forma:

 miarray[5]="calcetines verdes"

Es decir estoy metiendo en el sexto cajón (el referenciado por el índice 5) los «calcetines verdes»

También podemos llenar el armario de una vez:

miarray=(calcetines "camisetas blancas" "camisetas de color" "ropa interior")

En este caso estamos metiendo en el primer cajón los calcetines, en el segundo las camisetas blancas (las comillas están puestas para que no meta las camisetas en un elemento y blancas en otro), …

Igualmente podemos llenar el array con el contenido de un fichero y lo podemos hacer de dos formas:

si queremos que cada palabra vaya en un elemento

 miarray=(`cat fichero`)

si en cambio queremos que cada línea vaya en un elemento tendremos que ir metiendo en el array línea a línea:

i=0
while read linea ; do
   miarray[$i]=${linea}
   i=$(($i+1))
done <<< "`cat fichero`"

¿Cómo podemos sacar algo del armario?

Para acceder a un elemento del array se utiliza la siguiente sintaxis: ${nombre_del_array[indice]}
Es decir si queremos mostrar el tercer elemento de miarray (hay que tener siempre presente que la numeración empieza en 0 por lo que el tercer elemento será el número 2):

 echo ${miarray[2]}

¿Cómo saber cuántos cajones tiene el armario?
Se utiliza lo siguiente ${#nombre_del_array[@]}, por ejemplo si tenemos:

miarray=(calcetines "camisetas blancas"  "camisetas de color" "ropa interior")
echo ${#miarray[@]}

nos dará como resultado 4

¿Cómo leer un fichero?

Esto ya lo hemos visto cuando hemos tratado los arrays pero por si alguien no se ha dado cuenta lo repito. Para leer un fichero línea a línea lo más cómodo es utilizar un bucle while con read line. Es decir:

while read linea ; do
   echo ${linea}
done <<< "`cat fichero`"

en linea se va almacenando en cada iteración la línea del fichero que toque y para que el bucle while sepa de donde obtener los datos ponemos al final del bucle <<< para indicarle que los datos le van a llegar por esa vía, `cat fichero` para volcar el contenido del fichero y lo encerramos entre comillas dobles («) para que cada línea la trate como un todo, sin las comillas en cada iteración tomaría una sola palabra del fichero, es decir recorreriamos el fichero de palabra en palabra.

Naturalmente si nos interesara recorrer un fichero de palabra en palabra, por ejemplo porque es un fichero de configuración en el que cada línea es del tipo opcion=valor (así sin espacios), nos serviría con hacer lo siguiente:

contenido=`cat fichero`
for linea in ${contenido} ; do
  echo ${linea}
done

o sin utilizar la variable contenido:

for linea in `cat fichero` ; do
  echo ${linea}
done

¿Cómo «capturar» los parámetros de un script?

Los parámetros de un script se recogen en las variables especiales $n donde n es un número del 1 al 9.

Además también existe $0 que nos indica el nombre del script.

Si queremos saber el número de parámetros con el que nos han invocado al script podemos usar la variable especial $#

#!/bin/bash

if [ $# -lt 4 -o $# -gt 5 ]; then
  echo "Formato: $0 param1 param2 param3 param4 [param5]"
  exit 1
fi

echo Los parámetros son:
echo $1
echo $2
echo $3
echo $4
if [ $# -eq 5 ]; then
  echo $5
fi

Si nuestro script requiere más parámetros podemos usar shift para desplazar una posición los parámetros de forma que $1 pasa a almacenar el segundo, $2 el tercero, … y $9 el décimo, una nueva ejecución de shift haría que en $9 tuvieramos el undécimo parámetro y así sucesivamente.

#!/bin/bash

i=1
while [ $# -gt 0 ]; do
   echo El parametro $i vale $1
   i=$(($i+1))
   shift
done

Mediante la forma anterior podemos recuperar todos los parámetros que necesitemos pero esos parámetros tienen que estar ordenados para que se sepa a qué corresponde cada uno:

#!/bin/bash

directorio_origen=$1
fichero_origen=$2
directorio_destino=$3
fichero_destino=$4
cp ${directorio_origen}/${fichero_origen} ${directorio_destino}/${fichero_destino}

Es decir, en el absurdo script anterior cada parámetro tiene que tener siempre el mismo significado, el primero el directorio origen, el segundo el fichero a copiar, el tercero el directorio destino y el cuarto el nombre del fichero copiado.

Si por el contrario utilizamos unos parámetros especiales que nos identifiquen el siguiente parámetro no tendríamos esa limitación, es decir si por ejemplo un parámetro fuera -dd podría significar que el siguiente parámetro contiene el valor del directorio destino:

#!/bin/bash

while [ $# -gt 0 ]; do
  case $1 in
     -do) shift
	  directorio_origen=$1;;
     -dd) shift
	  directorio_destino=$1;;
     -fo) shift
	  fichero_origen=$1;;
     -fd) shift
	  fichero_destino=$1;;
  esac
  shift
done

cp ${directorio_origen}/${fichero_origen} ${directorio_destino}/${fichero_destino}

De esa forma no importa el orden de los parámetros y lo único que importa es que vayan emparejados correctamente, es decir que el fichero destino vaya después del parámetro -fd, el directorio origen después del parámetro -do, …

Y con esto doy por terminada esta segunda entrega.

Actualización

¿Cómo acceder a «subcadenas» de un string?

Cuando tenemos en una variable una cadena de texto puede interesarnos acceder a determinadas partes de la cadena, por ejemplo al carácter 5, al trozo de la cadena que empieza en el segundo carácter y tiene un tamaño de 3 caracteres, …

Por ejemplo, si tenemos en una variable la cadena «hola mundo», podemos querer sacar de uno en uno cada uno de los caracteres que la integran, es decir primero la h, luego la o, luego la l, …

En bash para acceder al carácter i de la variable x se utiliza la sintaxis ${x:i:1} siendo la x, el nombre de la variable, i la posición del primer carácter que queremos recuperar (hay que recordar que al igual que con los arrays se cuenta empezando en 0) y el 1 final indica el número de caracteres a recuperar.

#!/bin/bash

echo "Introduce una palabra o frase"
read frase

echo "'${frase}' comienza por ${frase:0:1}"

Mediante ${#variable} podemos saber la longitud de la cadena, lo que nos puede servir si queremos ir sacando los caracteres de la variable de uno en uno:

#!/bin/bash

echo "Introduce una palabra o frase"
read frase

echo "'${frase}' tiene ${#frase} caracteres que son:"
for ((i=0;i<${#frase};i++)) { 
  echo "$i - ${frase:$i:1}"
}

Así, darle la vuelta a una palabra o frase es muy sencillo:

#!/bin/bash

echo "Introduce una palabra o frase"
read frase

esarf=""
for ((i=$((${#frase}-1));i>=0;i--)) { 
  esarf=${esarf}${frase:$i:1}
}
echo "'${frase}' al revés es '${esarf}'"

Sorry, the comment form is closed at this time.