home
sabelotodo
logo
entrar
comentario
Djvu
colaborar

Elementos de Bash

Bash es un intérprete de comandos o lanza-programas, que funciona como idioma de programación y está integrado con los sistemas Linux  por defecto como parte indisoluble.

Tiene la ventaja de que su uso es mas simple que otros sistemas de programación y cualquiera persona con un poco de interés y algunos rudimentos de Bash puede escribir guiones que harán obedecer la PC en muchos campos. Su modo de operar es como "humanoide" es decir casi puede "conversarse" con la máquina tal y como si se hiciera con otra persona al escribir el guión, lo que lo convierte en el idioma de programación de los "iniciados" en este mundo, aunque este mismo modo de comunicación se utiliza muy parecido en otros idiomas de programación populares.

Su desventaja principal es que funciona a baja velocidad comparado con otros idiomas como C por ejemplo, por lo que para programas complejos no es apropiado.

Historia

Bash tiene su origen en la Shell de Unix, o Bourne Shell pero como esta Shell de Unix, era software propietario no podía utilizarse libremente.

Un día el movimiento mundial de software libre (free software) lo adoptó como propia y comenzó a reescribirla y a incorporarle nuevas funciones y capacidades en lo que se conoce como Bash (Bourne again shell) que traducido al Español es algo así como "de nuevo la shell de Bourne".

El Bash sigue siendo completamente compatible con sus predecesores y se desarrolla cada día mas, hasta ser un excelente aliado para el que quiere elaborar sus propios guiones.

Antes de empezar

Antes de empezar a tratar de aprender algo de Bash hay que saber algo de Linux, no pueden elaborarse guiones sin tener un conocimiento esencial integral del  sistema operativo Linux, así es que si va a intentar hacer sus primeros "experimentos" como "guionero" primero necesita entender como es el sistema y su construcción modular de multi-programas integrados que se interrelacionan formando una potente herramienta de trabajo. Algunas "horas de vuelo" sentado en una PC con Linux le ayudarán mucho, especialmente si está migrando de Windows, cuyas posibilidades reales de interacción son ridículas.
 En este articulo se utiliza mucho los términos proceso y programa, por eso es bueno aclarar brevemente sus significados.

Un programa es un archivo o conjunto de archivos que contienen código ejecutable y datos, el programa normalmente esta ubicado en un disco.
Se denomina proceso a un programa en ejecución, normalmente esta ubicado en memoria.

Puede suceder que el mismo programa se ejecute varias veces simultáneamente, produciendo varios procesos.

Por ejemplo supongamos dos usuarios en un sistema Linux , user1 y user2, ambos están utilizando el programa ls, user1 esta listando sus archivos (ls /home/user1) y el user2 también (ls /home/user2).

Ambos utilizan el mismo programa pero generan dos procesos distintos. Cada proceso tiene necesariamente un número de identidad con el cual el Kernel trabaja.

La consola

En Linux todo puede hacerse usando una consola de texto, incluyendo por supuesto el lanzamiento de programas, muchos de los cuales no tienen ninguna interfaz gráfica, no obstante en el escritorio (desktop) todas las distribuciones de Linux tiene una o mas consolas con interfaz gráfica que emulan la consola principal y permiten al usuario normal utilizar este servicio de manera mas fácil y amistosa. La utilización de la consola para obtener información sobre la disponibilidad de programas o su lanzamiento, sus opciones así como la prueba del guión mismo que se escribe serán en este mundo "el pan de cada día". esta consola representa la shell.

El comando

Un comando es comúnmente un texto escrito en la consola o en un guión que el sistema operativo buscará como ejecutable dentro de los directorios apropiados ($PATH) y lo ejecutará, si el comando es verdadero (corresponde a un ejecutable) la consola mostrará la salida de la ejecución, de lo contrario imprimirá el texto "comand not found" (no encuentro el comando).

La linea de comandos.

 La linea de comandos es una linea  de texto escrita de forma determinada en la consola o el guión, que puede ser interpretada por uno o mas programas en particular para ejecutar un trabajo determinado de acuerdo al contenido de la linea. Las lineas de comandos generalmente comienzan con el nombre del programa que ejecutará la primera acción solicitada. Casi siempre el programa se invoca utilizando el nombre del programa y puede ser seguido por una o mas opciones propias del programa que varían  de acuerdo al diseño seguido por el programador, esto puede ser variable, no obstante hay una receta bastante generalizada que se ha convertido en una suerte de estándar en los programas de Linux, esta es:

"nombre del programa"  "opciones"  "archivo de entrada"  "archivo de salida"

El primer argumento del comando invoca el programa en cuestión que ejecutará la acción, el segundo le indica al programa alguna forma de ejecución particular de la acción y los dos últimos le indican al programa cual archivo utilizará como "materia prima"  y donde debe colocar el "trabajo terminado". Repetimos que no es una receta única pero puede servir de ejemplo bastante usual.

La linea de comandos puede ser mas compleja e involucrar varios programas en una acción final solicitada.
En una misma linea de comandos pueden ejecutarse varios comandos si se separan con el carácter (;) y su ejecución será consecutiva, tal y cual se hubieran escrito en lineas diferentes.

Por lo general las opciones van precedidas por uno o dos guiónes (-) y una buena parte de los programas aceptan dos variantes de la opción, la corta (una letra) y la larga (una palabra), el clásico ejemplo es el de como indicarle a un programa que nos muestre la ayuda, casi siempre se obtiene el mismo efecto cuando se escribe como opción -h, o  --help.

Así tenemos que si usted en la consola escribe:

"sox -h", obtendrá el mismo efecto que si escribe "sox --help". Siempre hay que dejar un espacio entre cada una de las partes que conforman la linea de comandos. Bash interpreta este espacio vacío como el fin de una cosa y el comienzo de otra por defecto.

Esta ayuda es lo primero que debe usted buscar para saber como invocar el programa y que opciones tiene a su disposición. Una ayuda mas completa casi siempre se obtiene si escribe en la consola "man  nombre del programa", se imprimirá a la pantalla el manual. También algunos programas tienen la opción --longhelp que imprime una ayuda mas elaborada.

En Linux existen una gran variedad de programas que se instalan por defecto y otros que pueden instalarse adicionalmente que conforman un amplio arsenal para casi cualquier cosa que necesite hacer en su guión.

Un vistazo al comando "info coreutils" corrido en la consola le dará una muestra de algunos.

El guión

Un guión (script) para bash es un archivo de texto  que contiene una sucesión de comandos de Shell que pueden ejecutar diversas tareas de acuerdo al contenido del texto del guión. De esta forma pueden automatizarse muchas  acciones  para alguna necesidad particular o para la administración de sistemas. El guión debe escribirse en un orden lógico  pues Bash ejecutará el guión en el orden en que se escriben las lineas, de la misma forma que cuando se realiza una tarea cualquiera por una persona, por ejemplo; primero hay que poner la escalera y luego subirse.

Los guiones de Bash deben tener siempre como primera linea del guión el texto:

      #!/bin/bash

Esto indicará al sistema operativo que debe ejecutar la acción usando el programa Bash.

Una vez escrito el guión y guardado en el disco en alguno de los directorios "bin" con el nombre  y permiso  de ejecución apropiados, se invoca, escribiendo en la consola el nombre del guión.

Si el guión tiene una interfaz gráfica se invoca como otro programa cualquiera, uno o dos clic sobre el guión o su icono.

El guión puede escribirse en cualquiera de los editores de texto de Linux, por ejemplo Kwrite y será ya un guión funcional cuando se salve a alguno de los "bin". Es buena práctica cuando se escribe un guión salvarlo apenas se hayan escrito las primeras línea para ir comprobando su funcionamiento e ir corrigiendo los problemas.

Variables

Es impensable  elaborar guiones de Bash sin el uso de las variables. Una variable es una estructura de texto (una letra, un número o sucesiones de ellos) que representa alguno de los elementos que varían en valor y/o significado en el entorno de la Shell, sirviendo como elemento básico de entrada/salida de valores a y desde los comandos en su ejecución consecutiva. Para invocar una variable se utiliza el carácter especial $ precediendo al nombre de la variable.
Hay dos tipos de variables:

1.- Variables intrínsecas de Bash.

2.- Variables creadas por el programador.

Las variables intrínsecas son elaboradas por defecto por el propio Bash y son:

$0----------- Nombre del guión

$1....$n ----Variables que almacenan los n argumentos (opciones) proporcionados al comando.

$# ----------Variable que contiene el total de los argumentos proporcionados.

$* -----------Conjunto de los argumentos.

$? -----------Valor de ejecución del comando anterior, si es cero es que el comando anterior se ejecutó sin errores, de lo contrario hubo algún error.

$$----------- Identifica el proceso del guión.

$!------------ Identifica el último proceso arrancado en el trasfondo (background).

Las variables pueden ser creadas en cualquier momento, pero siempre antes de su utilización de manera muy simple, se escribe:

nombre_variable=valor_variable; en cualquier momento posterior a la creación si se coloca $nombre_variable dentro del entorno de la Shell el sistema colocará allí  valor_variable, ejemplo.

Variable:  SALUDO=Bienvenido

En cualquier momento posterior si se pone $SALUDO, Bash colocará ahí  Bienvenido.

Una variable también puede ser la salida de un comando si envolvemos este en el carácter (`) así por ejemplo el texto:

SALIDA=`comando`   le indicará al sistema que donde se escriba $SALIDA debe poner la salida de ese comando.

Es práctica común utilizar mayúsculas para las variables a fin de identificarlas fácilmente dentro del guión.

Cuando se ejecutan guiones que pueden ser "hijos" de otro guión en ocasiones es necesario exportar las variables, esto se hace escribiendo; export nombre_variable

Caracteres especiales

Existe un grupo de caracteres especiales (también llamados meta caracteres) que tienen significado propio para Bash. Algunos son:

\    ------ Le indica a Bash que ignore el carácter especial que viene después.

" " -----Cuando se encierra entre comillas dobles un texto o una variables si esta es una frase (cadena de palabras) Bash lo interpretará como una cadena única.

$    ------Identifica que lo que le sigue es una variable.

' '   ----- Las comillas simples se usan para desactivar todos los caracteres especiales encerrados dentro de ellas, así tenemos que si escribe '$VARIABLE' Bash interpreta literalmente lo escrito y no como variable.

#   ----- Cuando se coloca este carácter dentro de una linea del guión, Bash ignora el resto de la linea. Muy útil para hacer comentarios y anotaciones o para inhabilitar una linea de comandos al hacer pruebas.

;    ------ Este carácter se usa para separar la ejecución de distintos comandos en una misma linea de comandos.

``  ----- Se utiliza como se explicó en el punto anterior, para convertir la salida de un comando en una variable. El comando en cuestión se ejecuta en una sub shell.

También están |, (), !, >, <, cuyo significado se verá mas adelante. El espacio es otro carácter especial y se interpreta por bash como el separador del nombre del programa y las opciones dentro de la linea de comandos, por esta razón es importante encerrar entre comillas dobles el texto o las propias variables cuando son una frase de varias palabras.

Otro carácter que debe evitarse en lo posible su uso es el guión (-) ya que para la mayoría de los programas se usa para indicarle al propio programa que lo que sigue es una de sus opciones, de manera tal por ejemplo, si usted crea un archivo con nombre -archivo (en caso que pueda) después será difícil borrarlo ya que rm (programa que borra) tratará el archivo como una de sus opciones (al "ver" el guión) y dará de error  algo así, "Opción -archivo no se reconoce".

Palabras especiales

Hay un grupo de palabras que tienen significado especial para bash y que siempre que se pueda deben evitarse cuando se escriben lineas de comandos para no crearle "confusiones" algunas son: exit, break, continue, true, false, return etc... cuyo significado es mas o menos así:

exit  ---------------Se sale del guión.

break -------------Se manda explícitamente a salir de un ciclo.

continue ---------Se manda explícitamente a retornar en un ciclo.

return ------------Como exit pero solo se sale del comando u operación sin cerrar el guión.

true ---------------Indica que una condición es verdadera.

false --------------Indica que una condición es falsa.

Argumentos propios de bash*

Bash como programa tiene algunos argumentos útiles y propios que se usan con frecuencia en la elaboración de guiones en los condicionales vinculados a la determinación de elementos sobre los archivos, variables, cadenas de palabras o cadenas de pruebas, los mas comunes son:

Argumentos de Archivos
Cierto si.... (salida 0)
-d
Archivo existe y es un directorio
-c
Archivo existe y es de caracteres
-e
Archivo existe
-h
Archivo existe y es un vínculo simbólico
-s
Archivo existe y no está vacío
-f
Archivo existe y es normal
-r
Tienes permiso de lectura del archivo
-w
Tienes permiso de escritura en el archivo
-x
Tienes permiso de ejecución del archivo
-O
Eres propietario del archivo
-G
Perteneces al grupo que tiene acceso al archivo
-n
Variable existe y no es nula
Archivo1 nt Archivo2
Archivo1 es mas nuevo que Archivo2
Archivo1 -ot Archivo2
Archivo1 es mas viejo que Archivo2

Agumentos de cadenas
Cierto si
-z
La cadena está vacía
-n
La cadena no está vacía
cadena1 = cadena2
Si las cadenas son iguales
cadena1 != cadena2
Si las cadenas son diferentes
cadena1 < cadena2
Si la cadena 1 va antes en el orden lexicográfico
cadena1 >cadena2
Si la cadena 1 va despues en el orden lexicográfico

*
En realidad estos argumentos cuando se encuentran entre [ ], son un atajo al argumento correspondiente del programa test, que es un programa independiente pero que ha sido incorporado al propio Bash.

Entrada/salida

En algunas ocasiones será necesario leer ciertas variables desde el teclado o imprimirlas a la pantalla, para imprimir a la pantalla se pueden invocar dos programas en la linea de comandos:

echo

printf  (que es un echo mejorado)

y para leer desde el teclado se usa:

read

si hacemos un read sin asignar variable, el dato de almacena en $REPLY una variable del sistema. Tanto el comando echo como read tienen sus propias opciones.

Ejemplos:

1.-Si creamos en una linea del guión una variable como un comando y queremos imprimir la variable a la pantalla podemos hacer algo así:

VARIABLE=`comando`
echo "$VARIABLE"
 

La palabra $VARIABLE está puesta entre comillas dobles para que se imprima todo el texto ignorando los espacios entre palabras.

2.- Si escribimos en una linea del guión

read PREGUNTA;  habremos creado una variable de nombre PREGUNTA así es que si luego ponemos.

echo "$PREGUNTA"

se imprimirá a la pantalla lo que se escribió en el teclado al presionar la tecla Enter.

Con los elementos tratados hasta aquí ya podemos escribir nuestros primeros guiónes

Guión 1

#!/bin/bash
echo Hola mundo

Cuando se corre este guión se imprimirá a la pantalla Hola mundo

Guión 2

Lo mismo usando una variable
 
#!/bin/bash
VARIABLE=Hola mundo
echo "$VARIABLE"

Nótese la variable entre comillas dobles para que imprima todo el texto.

Guión 3

Cuando se usan mas de una variable

#!/bin/bash
VARIABLE=Hola
SALUDO=mundo
echo "$VARIABLE""$SALUDO"

En los tres casos se imprimirá a la pantalla Hola mundo

Guión 4

Si se usan caracteres especiales la cosa puede cambiar

#!/bin/bash
VAR=auto
echo "Me compré un $VAR"---------------Imprimirá Me compré un auto
echo 'Me compré un $VAR' ---------------Imprimirá Me compré un $VAR
echo "Me compré un \$VAR"--------------Imprimirá  Me compré un $VAR

Note como las comillas simples y el carácter \ hacen que Bash ignore la función del carácter especial $. Siempre las comillas simples harán que se ignore todos los meta caracteres encerrados entre ellas y \ solo el que sigue después.

Condicionales

Los condicionales son claves para "explicarle" a la máquina como debe proceder en una tarea cualquiera,  esto se hace casi como si se estuviera explicando una tarea a ejecutar a otra persona.

El condicional por excelencia tiene seis palabras claves que son if, elif, else, then y fi.

Donde las palabras tienen un significado comunicativo (en Inglés) casi literal, tal y cual se tratara con otra persona y que Bash por defecto las entienda con ese significado.

if    ---si condicional (de si esto o lo otro)

elif  ---también si (contracción de else if)

else ---De cualquier otra manera

then ---Entonces

fi -------if invertido, indica que se acabó la condicional abierta con if

Solo son imprescindibles en la estructura del guión if  then y fi.

Supongamos ahora que es usted el jefe de una oficina y  tiene una secretaria y que por alguna razón le han pedido que envíe  una copia de cualquier documento que lo identifique; normalmente le diría a la secretaria algo así:

"Maria, por favor, busca en el archivo alguna identificación" (condición a evaluar)
if  "si es una copia del pasaporte" (primer resultado de la condición); then (entonces)
" envíala por fax a...." (equivalente al comando a ejecutar)
elif    "si es de la licencia de conducción"  (segundo resultado de la condición); then
"envíala por correo" (otro comando a ejecutar)
elif  " si es del carnet de identidad" (tercer resultado de la condición); then
"envíala con un mensajero " (otro comando diferente)
else "de cualquier otra manera"
"pasa un fax diciendo que la enviaré mañana"  (otro comando)
fi

Observe que la acción a ejecutar (equivalente al comando) se hace si la condición se evalúa como verdadera de lo contrario se ignora y se pasa a la próxima, si ninguna es verdadera se ejecuta finalmente la acción después del else.

La sintaxis de bash  se debe tener en cuenta  a la hora de escribir el guión o de lo contrario Bash no entenderá lo que usted quiso decirle.

Pongamos ejemplos de guiones reales

Guión 5

#!/bin/bash
VAR1=Pablo
VAR2=Pedro
if [ "$VAR1" = "$VAR2" ]; then 
echo Son iguales
else
echo Son diferentes
fi

Los corchetes son parte de la sintaxis de Bash y en realidad son un atajo (shortcut) al programa test que es el que ejecuta la acción de comparación.
Observe siempre los espacios vacíos entre los elementos que conforman la linea de comandos (excepto entre el último corchete y el ;), recuerde que ese espacio vacío por defecto Bash lo interpreta como final de un elemento y comienzo de otro.

Si corre este guión siempre se imprimirá a pantalla  Son diferentes, ya que la condición es falsa. Pero si cambia el valor de VAR2=Pablo entonces se imprime Son iguales.

Guión 6

Un guión que verifica si existe un directorio y si no existe lo crea e imprime mensajes a pantalla comunicando la acción ejecutada.

#!/bin/bash
DIR=~/fotos  (crea como variable el directorio /home/fotos)
if [ ! -d "$DIR" ]; then  (verifica si  no existe el directorio)
mkdir "$DIR"  (si la condición es cierta, no existe el directorio, lo crea)
if [ $? -eq 0 ]; then (verifica si la acción se ejecutó sin errores, de serlo imprime lo que sigue)
echo "$DIR" ha sido creado..."
else  (de lo contrario imprime)
echo "Se produce un error al crear "$DIR"
fi (Se cierra la condición abierta en la realización del directorio segundo if)
else ( de lo contrario, relativo al primer if)
echo "Se usará "$DIR" existente"
fi

En este guión pueden verse varias cosas nuevas:

1.- El carácter ! niega la acción, si se hubiera escrito if [ -d "$DIR" ] lo que se estaba evaluando era la condición ¿existe el directorio"$DIR"? pero al colocar ! se evalúa lo contrario.

2.- El carácter ~ significa el /home del usuario.

3.- La expresión -eq se utiliza cuando quieren compararse valores numéricos, y significa =

4.- Se usa una de las variables del sistema "$?" explicada mas arriba.

5.- Pueden utilizarse unos condicionales dentro de otros siempre que se cierren apropiadamente.

Guión 7

#!/bin/bash
echo "Diga si o no:"
read VAR
if  [ "$VAR" = si ]; then
echo "Escribiste -si-"
elif [ "$VAR" = no ]; then
echo "Escribiste -no-"
elif [ "$VAR" = "" ]; then
echo "No puede dejarlo en blanco"
else
echo "Lo que escribió no se acepta"
fi

Observe que se está evaluando varias opciones de la misma condición por lo que lo apropiado es incorporar los respectivos elif dentro de la misma condicional.

Un elemento nuevo que se incorpora aquí es la condición " " que quiere decir "la variable está vacía", en este caso, cuando no se escribió nada.

Condicional case-in esac

Cuando una variable puede puede adquirir varios valores o significados diferentes, ya hemos visto como puede usarse la palabra elif  para hacer diferentes ejecuciones de comandos dentro de una misma condicional if-then-fi de acuerdo al valor de la variable. Una forma de realizar la misma acción sin escribir tantas lineas de condicionales elif y con ello disminuir el tamaño del guión es la utilización de la sentencia case-in-esac.
Esta sentencia permite vincular patrones de texto con conjuntos de comandos; cuando la variable de la sentencia coincide con alguno de los patrones, se ejecuta el conjunto de comandos asociados.

La sintaxis de la sentencia case-in esac es como sigue

case "nombre_variable" in
posibilidad 1)  "uno o mas comandos" ;;
posibilidad 2)  "uno o mas comandos" ;;
posibilidad n)  "uno o mas comandos" ;;
esac

Ejemplo

Guión 8

#!/bin/bash
echo "Diga si o no:"
read VAR   
case "$VAR" in
si) echo "Escribiste -si-" ;;
no) echo "Escribiste -no-" ;;
*) echo "Lo que escribió no se acepta" ;;
esac

Este guión es el mismo guión 7 pero utilizando la sentencia case-in-esac.

Observe que el carácter (*) utilizado en la última opción significa "patrón no contemplado" en este caso.

Funciones

Como mecanismo de estructuración en la codificación de guiones, existe la posibilidad de crear funciones. Su definición exige la definición de un nombre y un cuerpo. El nombre que debe ser representativo , es seguido de apertura y cierre de paréntesis, mientras que el cuerpo se delimita con llaves. La sintaxis es la siguiente.

nombre_función ()
{
uno o mas comandos
}

Una vez definida la función se utiliza como si de un comando se tratase, invocándolo con el nombre de la función. Hay que hacer una invocación de la función ya definida para que se ejecute el código en su interior y se convierta en operativa.

Las funciones son muy útiles cuando segmentos del código de guión son repetitivos, de tal forma solo se escriben una vez y se invocan todas las veces que haga falta, practicando el divino arte de la recursión.

Ejemplos

Creando una función simple

ayuda ()    (se define la función ayuda)
{
echo "Las opciones son si o no, luego apriete Enter"
}

Después de creada y activada la función, cada vez que necesitemos la "ayuda" dentro del guión solo colocamos la palabra ayuda como si se tratase de un comando mas y Bash ejecutará el código incluido dentro de la función, es decir imprimirá el texto "Las opciones son si o no, luego apriete Enter".

Las funciones pueden ser definidas en cualquier orden, pueden ser tantas como haga falta y pueden contener un paquete relativamente complejo de comandos. Un programador que ha pensado la estructura del guión antes de empezarlo puede y de hecho se hace, crear todas las funciones que necesitará al empezar el guión.

Pruebe lo siguiente

Guión 9

#!/bin/bash
salir ()  #(Se crea la función salir)
{
exit        #(comando)
}
hola()    #(Se crea la función Hola)
{
echo Hola   #(comando)
}
hola     # (Se invoca la función Hola)
salir     # ( Se invoca la función salir)
echo "Esto no se imprime nunca"

Verá que el último echo no se imprime ya que primero se invoca la función hola y luego la función salir que cierra el guión (exit). Trate ahora poniendo un comentario (#) a la linea que invoca la función salir (linea 11) y note la diferencia, vera como se imprime el último echo.

Observe también como se han comentado aquellas cosas que no son parte integrante del guión pero que se pueden escribir para hacer aclaraciones o anotaciones de interés.

Ciclos, lazos o bucles

Indistintamente llamados (loop) en Inglés, los ciclos permiten repetir una secuencia de acciones un cierto número de veces, ya sea fijo o determinado por el cumplimiento de una condición y pueden ser de tres tipos.

While-do-done

La sentencia while-do-done se utiliza para ejecutar un grupo de comandos en forma repetida mientras una condición sea verdadera. Su sintaxis es:

while
lista de comandos 1
do
lista de comandos 2
done

Mientras la condición de control (lista de comandos1) sea verdadera, se ejecutaran los comandos comprendidos entre do y done en forma repetida, si la condición da falsa (o encuentra una interrupción explícita dentro del código) el programa sale del bucle (se para) y continua la ejecución por debajo del while.

Un ejemplo de la utilidad de este lazo es la posibilidad de poder escoger varias opciones de un menú sin tener que correr el guión para cada opción, es decir se escoge y evalua una opción y el programa no se cierra, vuelve al menú principal y se puede escoger otra opción, tantas veces  como sea necesario.

Veamos un ejemplo de como elaborar un menú de opciones.

Guión 10

#!/bin/bash
while [ "$OPCION" != 5 ]
do
echo "[1] Listar archivos"
echo "[2] Ver directorio de trabajo"
echo "[3] Crear directorio"
echo "[4] Crear usuario"
echo "[5] Salir"
read -p "Ingrese una opción: " OPCION
case $OPCION in
1) ls;;
2) pwd;;
3) read -p "Nombre del directorio: " DIRECTORIO
mkdir $DIRECTORIO;;
4) if id | grep uid=0
then
read -p "Nombre del usuario: " NOMBREUSUARIO
useradd $NOMBREUSUARIO
else
echo "Se necesitan permisos de root"
fi;;
5);;
*) echo "Opción ingresada invalida, intente de nuevo";;
esac
done
exit 0

Descripción del guión.

1.-En la primera linea condicionamos el lazo a que la opción escogida sea diferente de 5.

2.-Luego se hace una lista de echos de las opciones desde 1 hasta 5 con su descripción para que sean imprimidas a la pantalla y así poder escoger alguna.

3.- Le sigue el comando read para que lea del teclado la opción escogida (variable OPCION), a read se le ha agregado -p que hace que imprima un mensaje, en este caso imprime Ingrese una opción.

4.-Para ahorrar lineas del guión se elabora un case con los comandos que deben ejecutarse en cada caso ls para listar los archivos [1], pwd (present work directory) para  ver directorio de trabajo [2], otro read para escribir el nombre del directorio que quiere crear [3] y hacer la variable DIRECTORIO seguido por mkdir que crea el directorio, luego se crea una condicional if-fi para chequear si el usuario tiene permisos de root, necesario para la opción [4] de crear un usuario rechazándolo de lo contrario, despues viene la opción [5] vacía que ejecuta el comando exit 0, finalmente se incluye "cualquier otra cosa" con el carácter *.

Este guión resulta interesante porque se usan las dos formas de compactar el guión vistas hasta ahora, la sentencia case-in-esac y la while-do-done. Además empiezan a aparecer incluidos en los comandos algunos de los programas muy usados de Linux al escribir guiones.

until-do-done

La sentencia until-do-done es lo contrario de while-do-done es decir el lazo se cierra o para, cuando la condición sea falsa. Si le parece que ambas son muy parecidas está en lo cierto.

En ambos casos se pueden elaborar bucles o ciclos infinitos si la condición de control es siempre verdadera o falsa según el caso, veamos:

Lazos infinitos

Bucles infinitos son aquellos donde la ejecución continua dentro del bucle indefinidamente, veamos como hacer un bucle infinito mediante while:

while true
do
comando 1
comando 2
comando n
done

La condición siempre es verdadera y se ejecutara el bucle indefinidamente, mediante until sería así:

until false
do
comando 1
comando 2
comando n
done

Existe la posibilidad de salir de un bucle, independientemente del estado de la condición, el comando break produce el abandono del bucle inmediatamente.

Veamos el guión anterior sobre la creación de un menú utilizando un lazo infinito y el comando break

Guión 11

while true
do
echo "[1] Listar archivos"
echo "[2] Ver directorio de trabajo"
echo "[3] Crear directorio"
echo "[4] Crear usuario"
echo "[5] Salir"
read -p "Ingrese una opción: " OPCION
case $OPCION in
1) ls;;
2) pwd;;
3) read -p "Nombre del directorio: " DIRECTORIO
mkdir $DIRECTORIO;;
4) if id | grep uid=0
then
read -p "Nombre del usuario: " NOMBREUSUARIO
useradd $NOMBREUSUARIO
else
echo "Se necesitan permisos de root"
fi;;
5)
echo "Abandonando el programa..."
break;;
*)
echo "Opción ingresada invalida, intente de nuevo";;
esac
done
exit 0

for-in-done

Es otro tipo de ciclo o lazo disponible, la diferencia con los anteriores es que no se basa en una condición, sino que ejecuta el bucle una cantidad determinada de veces, su sintaxis es la siguiente:

for variable in arg 1 arg 2 ......arg n
do
comando 1
comando 2
comando n
done

Ejemplos

Guión 11

for LETRA in a b c d e f
do
echo $LETRA
done

En este guión el comando echo  se ejecutara tantas veces como argumentos se hayan puesto después del in, por lo tanto imprimirá seis lineas cada una con una letra de la a a la f.

Guión 12

for ARCHIVO in *
if [ -d $ARCHIVO ]; then
cd $ARCHIVO
rm *.tmp
cd ..
fi
done

Este es un guión entra en todos los subdirectorios del directorio actual de trabajo y borrará todos los archivos .tmp (temporales).

En este caso el carácter * se usa en la primera linea con el significado "tantas veces como sea necesario" y en la penúltima linea como "cualquier cosa".

Redireccionamiento

Es frecuente la necesidad de redirigir  resultados de la ejecución de un comando a diferentes lugares, que pueden ser los descriptores de ficheros stdin, stdout y stderr, a la entrada de otro comando o a un archivo en el disco duro, esto se llama redirección y es muy útil en la escritura de guiones.

Los descriptores de archivos.

En Bash al igual que en cualquier otro programa de consola de Linux tenemos tres flujos o descriptores de archivos abiertos por defecto:

La entrada estándar (STDIN)

La salida estándar (STDOUT)

El error estándar (STDERR)

El primero puede ser utilizado para leer de él, y los otros dos para enviar datos hacia ellos. Normalmente STDIN viene del teclado de la terminal en uso, y tanto STDOUT como STDERR van hacia la pantalla. STDOUT muestra los datos normales o esperados durante la ejecución, y STDERR  se utiliza para enviar datos de depuración o errores. Cualquier programa iniciado desde el shell, a menos que se le indique explícitamente, hereda estos tres descriptores de archivo permitiendole interactuar con el usuario.

Enviar STDOUT a un archivo

En ocasiones necesitamos enviar la salida estándar a un archivo y no a la pantalla, ya sea porque es muy grande para "manejar a ojo" o porque nos interesa guardarla a disco duro. Para enviar la salida estándar a un archivo usamos > con lo que se sobreescribe el archivo si ya existe, o >> que solo agrega los datos de salida al final del archivo ya existente.
Ejemplo

Guión 13

#!/bin/bash
ls -R /home/mis_fotos > /tmp/indice
 
Creará un archivo llamado  /tmp/indice donde estará el listado de los archivos bajo /home/mis_fotos.

Tomar STDIN de un archivo

Si queremos que un proceso tome su entrada estándar de un archivo existente usamos < como es el caso por ejemplo de los procesos que piden datos de confirmación (nombre de usuario, contraseña etc). Para esto creamos un archivo con los datos de confirmación y agregamos un < antes del comando que ejecutará el proceso.

Enviar STDERR a un archivo

Si queremos enviar la salida de errores a un archivo se procede igual que lo que se mencionaba con respecto a la salida estándar pero se usa &>  o &>> segun el caso.

Enviar STDERR a STDOUT

Para esto se escribe al final de la linea de comandos 2>&1.

Enviar STDOUT a STDERR

En este caso se escribe al final de la linea de comandos 1>&2

Entubado

Las tuberías se utilizan para enviar la salida de un comando o proceso a la entrada de otro, esto es con frecuencia necesario para completar una acción iniciada con un comando que debe ser completada con otro. Es simple el modo de operar, solo se coloca el carácter | en la linea de comandos entre un programa y otro. Este carácter (|) se conoce como tubo (pipe).

Ejemplo

Guión 14

#!/bin/bash
file -b "$1" | grep -i "vorbis" >/dev/null 2>&1
if [ $? -eq 0 ]; then
oggdec "$1"
echo  "Hecho"
else
echo "Archivo no soportado"
exit
fi

Este guión convierte a wav cualquier archivo de audio ogg.

Primero se invoca a file para que analice el tipo de archivo correspondiente a la variable $1 que como ya se sabe es el primer argumento introducido  en la linea de comandos (por ejemplo la ruta hasta un archivo). Luego la salida de file se entuba al programa grep que determina si dentro del archivo aparece la palabra vorbis (caso de los archivos de audio ogg).

El condiciomal if- then-fi chequea que sea cierto (es decir la palabra vorbis si existía, por lo que es un archivo ogg de audio), entonces se decodifica a wav con el comando oggdec,  de lo contrario se imprime que es un archivo no soportado.

Tanto la salida estándar como la de errores se envía a /dev/null, un dispositivo que "desaparece" la información suprimiendo la salida por pantalla. Esto es conveniente y saludable en muchas lineas de comandos cuando la salida puede generar gran cantidad de información tanto de salida estándar como de errores y estos no nos interesan. Solo se escribe >/dev/null 2>&1.

Aliases

Podemos indicarle a Bash que cada ves que le demos una estructura de texto la sustituya por otra, eso se hace con el comando alias.

Cuando bash ejecuta cualquier proceso, verifica si la primera palabra que tengan todos los comandos aparecen en su lista de aliases y la sustituye antes de seguir ejecutando la linea. La sintaxis para crear un alias es como sigue: alias algo='comando', por ejemplo:

alias lista='ls -l'.

Cada vez que pongamos la palabra lista como un comando Bash ejecutará ls -l.

Ahora, si escribimos echo lista, como no es la primera palabra imprimirá lista a secas, pero si ecribimos echo `lista` nos imprimirá el resultado de ls -l ya que lo encerrado entre comillas invertidas se ejecuta en un sub shell para la cual la primera palabre es lista.

Pueden definirse tantos aliases como necesitemos para trabajar con comodidad y ahorrarnos teclazos. Para consultar la lista de aliases se ecribe en la consola alias sin argumentos.

Para eliminar los aliases se escribe unalias y el nombre. Las distribuciones y los propios programas instalados ya vienen por defecto con varios aliases, haga la prueba en el suyo.

Globales y expansiones.

Globales

Estos son aliados cuando uno quiere ahorrarse teclazos y funcionan como "generalizadores" de cosas, los globales mas comunes son:

1. ~  Le dice a Bash que es el directorio home del usuario.

2. *   Significa "todo lo que puedas incluir ahí" de forma tal que si ponemos el comando ls ~/*.wav listará todos los archivos .wav que están en el directorio home del usuario. Ahora si escribimos ls ~/m* nos listará todos los archivos de home que empiecen con m.

3.- .  Un punto en el entorno de la shell significa "el directorio donde estamos trabajando" Ejemplo:

Guión 15

#!/bin/bash
DIR=.
mkdir "$DIR"
echo "$?"

Si escribimos este guión  y lo corremos dará un error.  Por supuesto, le estamos mandando a hacer el directorio donde estamos. Habrá notado usted que es muy común a la hora de compilar programas desde el binario utilizar  ./configure, con esto le estamos diciendo a Bash "corre el archivo configure que está en este mismo directorio".

Expansiones

Las expanciones son mas configurables y trabajan con argumentos mucho mas definidos, está claramente hecha para hacer mas inteligente la shell.
Cuando especificamos una lista de valores o argumentos separados por comas entre llaves, Bash  la expande convirtiéndola en la cadena expandida con cada uno de los argumentos, por ejemplo:

el comando; echo este/directorio/{algo,muy,demasiado}/largo dará como resultado la impresión a pantalla de:

este/directorio/algo/largo este/directorio/muy/largo este/directorio/demasiado/largo.

Hay que tener en cuenta que:

1.- La expansión funciona sobre una sola palabra sin espacios si escribimos:
echo esto {es,parece} difícil

escribirá;

esto es parece difícil

2.- La expansión no se realiza entre comillas simples ni dobles por lo que no sirve para corregir el ejemplo anterior:

echo "esto {es,parece} difícil"

dará:

esto  {es,parece} difícil

3.- Lo que debe hacerse es ignorar o escapar los espacios y escribir:

echo esto\ {es,parece}\ confuso

así obtendremos lo que queríamos:

esto es difícil esto parece confuso.

Pueden ponerse múltiples expansiones en una sola linea y se obtendrán todas las combinaciones posibles.

echo {una,otra}\  combinación\  { bastante,muy}\ difícil.

Responde

una combinación bastante difícil. otra combinación bastante difícil. una combinación muy difícil. otra combinación muy difícil.

Aritmética de Bash

Se pueden ejecutar en Bash las principales acciones aritméticas entre las variables utilizando los signos:

 +     -----suma

 -     -----resta

 *      -----multiplicación

 /       ------división
 
Las operaciones tienen su sintaxis que debe ser respetada para que Bash lo haga adecuadamente.

1.- Pruebe esto en la shell o la linea de comandos (consola).

echo 1+1, la respuesta será 1+1 porque bash lo interpreta como caracteres simples, para que realice la operación de suma hay que escribir:

echo $((1+1))  o echo $[1+1]

Bash no maneja números fraccionarios solo números enteros por lo tanto si usted escribe:

echo $[3/4]  la respuesta será cero, sin embargo, si escribe:

echo $[4/2]  la respuesta será correcta 2

2.- También podrá utilizar a expr para las operaciones de la forma siguiente:

expr argumento1 signo argumento2

pruebe en la consola:

expr 2+2  la respuesta será 4  o expr 4 / 2  la respuesta será 2.

Cuando se use es signo * para la multiplicación debe anteponerle una barra invertida para que Bash no lo interprete como un global, sería:

expr 10 \* 10  la respuesta será 100

El programa expr da sus resultados directamente a la salida estándar pero tampoco maneja números fraccionarios. Hay que observar siempre un espacio entre los argumentos.

3.-Para operar con fraccionarios debe entubar la expresión al programa bc de la forma siguiente:

echo operación | bc -l   por ejemplo;

echo 3/4 | bc -l

el resultado será 0.75  o

echo 2+2.5 | bc -l

devolverá 4.5

En algunas distribuciones el programa bc no se instala por defecto.

Hay otras expresiones que Bash interpreta aritméticamente;

-lt
Menor que
-le
Menor o igual que
-eq
Igual que
-ge
Mayor o igual que
-gt
Mayor que
-ne
 Distinto que

Lógica de Bash.

Para la shell los caracteres que tienen un significado lógico en la comparación o evaluación de archivos son:

>
Mayor que
<
Menor que
>=
Mayor o igual que
<=
Menor o igual que
!
Diferente que
||
OR  (ó)
&&
AND (y)
Ejemplo:

Guión 16

#!/bin/bash
ARCHIVO=$1
file -b "$1" | grep -i 'JPEG' || file -b "$1" | grep -i 'GIF' || file -b "$1" | grep -i 'PNG' || file -b "$1" | grep -i 'BITMAP' >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo "Es una imagen"
else "No es una imágen"
fi

En este guión hemos supuesto que un archivo cualquiera se convierte en la variable $1 y queremos averiguar si el archivo es una imágen  en alguno de los formatos mas comunes, primero acudimos a file para que "lea" el texto que contiene el archivo y lo entubamos a grep que buscará patrones de texto de lo que le entrega file. Como necesitamos averiguar si alguno de los patrones JPEG, GIF, PNG o BITMAP aparece dentro del archivo utilizamos varias instancias de file y grep separadas con OR (||), de esta forma le estamos diciendo en el comando "busca si aparece JPEG o GIF o PNG o BITMAP, si lo encuentras entonces imprime".
 
"Es una imagen" de cualquier otra forma imprime "No es una imagen"

Consideraciones finales

No existe forma alguna de que se aprenda Bash que no sea usándolo, son tantas y tan variadas las herramientas a su disposición así como las vías para lograr un objetivo que solo la experiencia puede ayudarle a aprenderlo.  Al principio le parecerá inalcanzable pero  si persevera se dará cuenta de que es posible y hasta fácil, después que uno le encuentra "las cosquillas" dirá con orgullo "esto es pan comido" cuando quiera automatizar una tarea o quiere hacer un "programita" para cumplir un objetivo. Haga lo mismo que yo, empecé jugando y ya he aprendido algo. Le deseo suerte.

Otros temas de informatica aquí.
Para ir al índice general de portal aquí.