Programación en Bash
De Proyectos GULIX
bash es una de tantas shell de Linux, la más popular en las distribuciones recientes como Ubuntu, Fedora o Mandriva. En la actualidad la gran mayoría de los scripts de configuración de las distribuciones de Gnu/Linux están programados en Bash, lo tanto para quien desee personalizar su sistema a fondo, tener conocimientos de bash es crítico.
En esta breve guía mostraremos varios ejemplos de programación en bash como ejemplo de los ciclos y sentencias de control vistas.
Dudas básicas antes de comenzar
¿Qué es un shell?
- El shell es un interprete de comandos.
- Pero también es un lenguaje.
- El conjunto de comandos es un script.
- Un script sirve como 'pegamento' de diversos comandos sencillos, que en conjunto son considerablemente poderosos.
¿Por qué aprender a programarlo?
- Te evita hacer tareas repetitivas.
- Es bueno conocerlo.
- Es fácil de aprender: piensa que quieres hacer - escríbelo - revísalo (ahora ponlo todo en un archivo o script).
- Usualmente no tienes que debugear mucho, es como si vaciaras lo que harías en el prompt de comandos, pero escrito en un archivo.
- Es ideal para hacer algunos prototipos.
¿Cómo creo un script?
- Crea un archivo miscript.sh con tu editor de textos favorito.
- Dale permisos de ejecución: $chmod +x miscript.sh.
chmod +x miscript.sh.
- Ejecutalo: $./miscript.sh
./miscript.sh
introducción
Para programar en bash se pueden utilizar todos los comandos del sistema, llamadas a otros script bash, funciones internas, y rutinas en otros lenguajes, estas características hacen que bash sea una herramienta potente que no pasa de moda.
hola mundo
#!/bin/bash echo "Hola Mundo"
En este ejemplo, la primera línea le indica al sistema qué programa ejecutará el resto de instrucciones que están en el script. En este caso el programa es bash y la ruta donde esta ubicado el binario es /bin/bash. La segunda línea es una instrucción de bash, que permite imprimir en pantalla la frase "Hola Mundo"
Si quisiéramos usar variables, podemos crear un hola mundo como sigue:
#!/bin/bash saludo="Hola Mundo" echo $saludo #esto escribe Hola Mundo
De este par de ejemplos podemos ver básicamente los siguientes puntos:
- un programa en bash comienza por buena costumbre con #!/bin/bash
- al crear una variable se coloca el nombre de la variable seguido por un = y el valor que contendrá
- al invocar una variable se le antepone el signo $ al nombre de esta.
- los comentarios empiezan con #
nota
entre la variable, el = y el valor no deben existir espacios
Una tercer versión del hola mundo puede ser la siguiente:
#!/bin/bash saludo="Hola" echo "$saludo Mundo"
Notese que con las comilla sigue siendo el resultado el mismo (Hola Mundo) y no $saludo Mundo
utilización de variables
Ya comenzamos en la sección hola mundo a ver la utilización de variables, pero su potencialidad es mayor, dado a que se puede almacenar un una variable el resultado de alguna operación, por ejemplo, podriamos crear un bash que nos salude dando algunos datos del día y semana del año en curso, como el script que sigue:
#!/bin/bash ddY=$(date +%j) smY=$(date +%U) echo "Hola, hoy es el dia $ddY del año y esta es la semana $smY"
Notemos que para asignar un valor de un comando, este necesita ser evaluado, para ello es que se utiliza el $( )ç
Evaluaciones numéricas
un ejemplo.
#!/bin/bash total=$((1+1)) echo $total
Utilizando let
#!/bin/bash let x=1 # le asigno 1 a x let x+=1 # lo incremento en 1, el termino += es equivalente al de C echo $x # muestra 2
let permite utilizar asignaciones y operaciones de asignación equivalentes a las de C, otras operaciones son
- incremento +=
- decremento -=
- mutiplicar por *=
- dividir por /=
- modulo por %=
- incremento en 1 ++
- decremento en 1 --
Utilizando read
read se usa para leer una variable desde la entrada común stdin
#!/bin/bash echo -n "ingrese su nombre: " read nombre echo "Hola $nombre"
Concatenación de cadenas
un ejemplo.
#!/bin/bash cadena1="hola" espacio=" " cadena2="mundo" echo $cadena1$espacio$cadena2
Caracteres especiales
- # indica un comentario
- ; separador, permite tener dos o más instrucciones en la misma linea
- ;; terminador de bloques en la instrucción case
- : instrucción que no hace nada, el típico NOP (do-nothing operation)
- ! indica negación
- * indica todo, si se usa como operación arimética, indica multiplicación
- ** multiplicación exponencial.
Sentencias de Control
Antes de comenzar con las sentencias propiamente tal, nos detendremos en un par de operadores para crear las sentencias condicionales y así poder armar algunas expresiones a evaluar.
algunos operadores
Operadores para operaciones numéricas y lógicas
- No !
- y &&
- o ||
- menor o igual -le
- mayor o igual -ge
- mayor que -gt
- menor que -lt
- igual que -eq
- distinto que -ne
- operador lógico AND -a
- operador lógico OR -o
Operadores para la gestión de archivos
- -f Si es un archivo tradicional
- -d Si es un directorio
- -r Si tiene permisos de lectura
- -w Si tiene permisos de escritura
- -x Si tiene permisos de ejecución
- -s Si tiene una longitud mayor que cero
if else
ejemplos:
#!/bin/bash if((4 < 6)); then echo "cuatro es menor que seis" fi
#!/bin/bash if((4 > 6)); then echo "cuatro es mayor que seis" else echo "cuatro no es mayor que seis" fi
case
ejemplo: el siguiente script recibe un parametro e indicará el valor el palabras, en caso que sea uno de los que estén en la lista de lo contrario no hará nada.
#!/bin/bash numero=$1 case $numero in 1) echo "uno" ;; 2) echo "dos" ;; 3) echo "tres" ;; 4) echo "cuatro" ;; 5) echo "cinco" ;; 6) echo "seis" ;; 7) echo "siete" ;; 8) echo "ocho" ;; 9) echo "nueve" ;; esac
for
Un ejemplo típico de for es borrar todos los archivos de respaldo .bkp de los subdirectorios. En una linea de comando sería:
for i in $( find | grep "\.bkp" ); do echo "borrando $i"; rm -rf $i; done
En un script
#!/bin/bash
for i in $( find | grep "\.bkp" );
do
echo "borrando $i"
rm -rf $i
done
En pocas palabras, lo que está haciendo el for, es lo siguiente:
- para cada i en lo encontrado por la sentencia find | grep "\.bkp"
- muestra "borrando $i"
- borra $i
veamos otro ejemplo de un for aplicando la lógica tradicional de los lenguajes de programación.
#!/bin/bash
cadena=""
for((a=0;a<8;a++))
do
cadena=$cadena$a
echo $cadena
done
donde se obtiene como resultado lo siguiente:
./lala.sh 0 01 012 0123 01234 012345 0123456 01234567
while
ejemplo:
#!/bin/bash CONTADOR=0 while [ $CONTADOR -lt 10 ]; do echo El contador es $CONTADOR let CONTADOR=CONTADOR+1 done
until
ejemplo:
#!/bin/bash
CONTADOR=20
until [ $CONTADOR -lt 10 ]; do
echo CONTADOR $CONTADOR
let CONTADOR-=1
done
Funciones
La utilización de funciones dentro de cualquier script pueden simplificar mucho el código, además de mejorar estéticamente la presentación y comprensión del mismo.
vemos un ejemplo simple :
#!/bin/bash
function funcion1 {
echo "estamos en la 1 y le pasamos el parametro:"$1
}
function funcion2 {
echo "estamos en la 2 y le pasamos el parametro:"$1
}
# ahora a ejecutarlas!
funcion1 hola
funcion2 chao
la salida en este caso es la siguiente:
estamos en la 1 y le pasamos el parametro:hola estamos en la 2 y le pasamos el parametro:chao
Menús de selección sencillos
un ejemplo simple:
#!/bin/bash
echo "te gusta el loly?"
OPCIONES="si no"
select opt in $OPCIONES; do
if [ "$opt" = "si" ]; then
echo que bien!
exit
elif [ "$opt" = "no" ]; then
echo que mal!
exit
fi
done
Ejemplos
Ejemplo1: Script para recodificar todos los archivos .mp3 de un directorio especificado en la linea de comandos.
El objetivo es lograr un Script que permita recodificar los archivos Mp3 de un directorio específico, por ejemplo pasar todo un disco de 192Kbps a 128Kbps. La lógica nos dice que se deben seguir los siguiente pasos:
- paso 1 : entrar al directorio donde están nuestros archivos a recodificar.
- paso 2 : solo para cada uno de los archivos que sean .mp3, se realizarán los siguientes pasos.
- paso 3 : verificar si el archivo corresponde a un archivo y no a un link o un directorio.
- paso 4 : recodificar el archivo y guardarlo con otro nombre.
- paso 5 : ya no necesitamos el archivo viejo, asi que lo borramos.
- paso 6 : renombrar nuestro nuevo archivo recodificado con el nombre que tenía el archivo que borramos.
- paso 7 : si quedan más archivos por recodificar, volver al paso 2.
script:
#!/bin/bash
cd "$1"
for i in *.mp3
do
if [ -f "$i" ]; then
lame -h -b 128 "$i" "$i.mp3"
rm "$i"
mv "$i.mp3" "$i"
fi
done
El comando cd $1, nos permite entrar al directorio que le hemos indicado al script como parámetro. El comando for nos permite barrer todos los archivos que se filtren mediante la expresión *.mp3, es decir todos los archivos que terminen su nombre con .mp3. El comando if, permite asegurarse que el archivo realmente es un archivo y no un link roto o una carpeta, el comando lame es un codificador de audio, que en este caso se encargar de recodificar el archivo de turno en el for.
Ejemplo2: calcular el digito verificador de un rut chileno
#!/bin/bash
# generar el digito verificador a partir del rut sin digito :)
# by Lacosox.org
rut=12345678
div=1
serie=2
sum=0
verificador=0
for((a=0;a<8;a++))
do
temp=$((rut/div))
div=$(($div*10))
if [ $serie = "8" ]; then
serie=2
fi
sum=$(((((($temp-((((rut/div))*10))))*serie))+$sum))
serie=$(($serie+1))
done
verificador=$((11-(($sum%11))))
if [ $verificador = "10" ]; then
verificador=k
fi
if [ $verificador = "11" ];then
verificador=0
fi
echo "rut completo: "$rut"-"$verificador
Ejemplo 3 : Cada 10 minutos mostrar el mensaje "Anda a estudiar!"
#!/bin/bash #by lacosox.org total=$((10*60)) # 10 minutos son 10*(60 segundos) while ((0==0)); do sleep $total echo "Anda a estudiar!" done
Ejemplo 4: Función LastIndexOf para bash
Este método devuelve la primera posición dentro del String donde comienza la subcadena pasada como argumento, pero realizando la búsqueda de derecha a izquierda.
#!/bin/bash
#Función LastIndexOf by lacosox.org
# retorna la posición donde está la subcadena, buscando de atrás hacia adelante, si no existe, retorna 0.
#
function lastIndexOf {
todo=$1;
cadena_a_buscar=$2;
largo_todo=${#todo};
largo_cadena_a_buscar=${#cadena_a_buscar};
if [ $largo_todo -ge $largo_cadena_a_buscar ];then
for((a=$(($largo_todo-$largo_cadena_a_buscar));a>=0;a--))
do
subcadena=${todo:a:largo_cadena_a_buscar};
if [ $subcadena = $cadena_a_buscar ];then
echo $((a+1));
break;
fi
done
else
echo "0";
fi
}
Ejemplo de uso:
function lastIndexOf {
todo=$1;
cadena_a_buscar=$2;
largo_todo=${#todo};
largo_cadena_a_buscar=${#cadena_a_buscar};
if [ $largo_todo -ge $largo_cadena_a_buscar ];then
for((a=$(($largo_todo-$largo_cadena_a_buscar));a>=0;a--))
do
subcadena=${todo:a:largo_cadena_a_buscar};
if [ $subcadena = $cadena_a_buscar ];then
echo $((a+1));
break;
fi
done
else
echo "0";
fi
}
si=`lastIndexOf "esta es la cadena esta" "ta"`;
echo $si
salida:
dalacost@lacosox.org:~$ ./test.sh 21
Ejemplo 5: Borrar archivos desde una lista predefinida en otro archivo
Primero editaremos un archivo que contendrá la lista de archivos a borrar, luego construiremos un script que lea este archivo y borre linea a linea los archivos.
para crear el archivo, debemos tener en cuenta la forma que tendrá el script para leer cada linea y borrar cada uno de los nombres que en el archivo se listen.
la herramienta tree nos ayuda a listar archivos con sus rutas completas. Lo que será de gran ayuda para ejecutar el script sobre cualquier directorio.
listando todos los archivos que contengan en su nombre los caracteres ".jpg" y guardando en un archivo.
$tree -i -f | grep .jpg > lista_de_archivos_a_borrar.txt
Luego el script sería de la siguiente manera.
for linea in $(cat lista_de_archivos_a_borrar.txt); do rm $linea; done
Ejemplo 6: Listando el tamaño de un archivo o directorio
Listará el tamaño de un archivo o directorio que se le entrega como parámetro, indicará un mensaje de error en caso que la ejecución no sea la correcta.
#!/bin/bash
Error(){
echo "Error. Sintaxis de uso: $0/ archivo | directorio"
}
if [ $# -lt 1 ]; then
Error
elif [ -d $1 ]; then
echo "$1 es un directorio y su tamaño es el siguiente:"
du -hs $1
elif [ -f $1 ]; then
echo "$1 es un archivo regular y su tamaño es el siguiente:"
du -hs $1
else echo "$1 no existe."
fi
Otra opción sencilla es la utilización del comando du:
#Ejemplo 1 para saber tamaño total del home de usuario knx (incluye tamaño de todos los subdirectorios) du -h -s /home/knx/ # Ejemplo 2 , lo mismo pero con detalle du -h /home/knx/
Ejemplo 7: Obteniendo un calendario para la oficina desde terminal
Para ejecutar este script debes tener instalado la herramienta cowsay, para instalar esta utilidad en debian solo debes ejecutar el comando apt-get install cowsay.
Este ejemplo de script esta escrito completamente desde la terminal, es decir no está dentro de un archivo que luego se ejecuta. Sin embargo igualmente es posible utilizar las sentencias de bash directamente, siempre y cuando estas estén bien utilizadas.
root@fenix:/home/knx# cowsay -f tux Calendario 2009-2010 de lo que queda del \
gobierno del CEII actual && cal -3m 11 2009 && c=2;while [ $c -lt 10 ];\
do cal -3m $c 2010;let c=c+3;done
______________________________________
/ Calendario 2009-2010 de lo que queda \
\ del gobierno del CEII actual /
--------------------------------------
\
\
\
.--.
|o_o |
|:_/ |
// \ \
(| | )
/'\_ _/`\
\___)=(___/
octubre 2009 noviembre 2009 diciembre 2009
lu ma mi ju vi sá do lu ma mi ju vi sá do lu ma mi ju vi sá do
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30
enero 2010 febrero 2010 marzo 2010
lu ma mi ju vi sá do lu ma mi ju vi sá do lu ma mi ju vi sá do
1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 6 7
4 5 6 7 8 9 10 8 9 10 11 12 13 14 8 9 10 11 12 13 14
11 12 13 14 15 16 17 15 16 17 18 19 20 21 15 16 17 18 19 20 21
18 19 20 21 22 23 24 22 23 24 25 26 27 28 22 23 24 25 26 27 28
25 26 27 28 29 30 31 29 30 31
abril 2010 mayo 2010 junio 2010
lu ma mi ju vi sá do lu ma mi ju vi sá do lu ma mi ju vi sá do
1 2 3 4 1 2 1 2 3 4 5 6
5 6 7 8 9 10 11 3 4 5 6 7 8 9 7 8 9 10 11 12 13
12 13 14 15 16 17 18 10 11 12 13 14 15 16 14 15 16 17 18 19 20
19 20 21 22 23 24 25 17 18 19 20 21 22 23 21 22 23 24 25 26 27
26 27 28 29 30 24 25 26 27 28 29 30 28 29 30
31
julio 2010 agosto 2010 septiembre 2010
lu ma mi ju vi sá do lu ma mi ju vi sá do lu ma mi ju vi sá do
1 2 3 4 1 1 2 3 4 5
5 6 7 8 9 10 11 2 3 4 5 6 7 8 6 7 8 9 10 11 12
12 13 14 15 16 17 18 9 10 11 12 13 14 15 13 14 15 16 17 18 19
19 20 21 22 23 24 25 16 17 18 19 20 21 22 20 21 22 23 24 25 26
26 27 28 29 30 31 23 24 25 26 27 28 29 27 28 29 30
30 31
root@fenix:/home/knx#
Link donde encontrar más ayuda
- Guía avanzada http://www.tldp.org/LDP/abs/html/index.html
- Guía de introducción a la programación en Bash, en español [1]
- Libro "El shell Bash", muy completo sobre todo de la bash de Unix. [2]
- Administración_de_usuarios_y_grupos_de_usuarios
- Comandos_básicos_en_Linux

