Hoy estrenamos nueva serie, en la que hablaré sobre scripts en Bash.
Los scripts son sencillos programas interpretados (no requieren compilación) que hacen, básicamente, lo mismo que puede hacer un usuario real en consola: llamar a un comando o un programa y decirle qué hacer. Además, el lenguaje permite cosas como saltos condicionales (si ocurre esto, haz esto otro), almacenar información en variables, leer y escribir archivos... lo que lo hace muy potente para automatizar tareas de todo tipo.
No es un curso de scripting: yo no soy programador ni pretendo serlo, y no tengo el nivel para dar lecciones a nadie. La serie va a tratar sobre algunos scripts que utilizo, que he creado y para qué sirven.
La primera mitad de cada artículo estará orientada a usuarios a los que les pueda resultar útil un script, que ni saben ni tienen por qué saber cómo funcionan las tripas de un programa, pero sí cómo usarlo. Vendrá una explicación de lo que hace el script, un enlace de descarga y una pequeña guía de uso.
En la segunda mitad intentaré explicar cómo funciona el script y cómo usar a mano cada una de las herramientas utilizadas en el script.
En esta primera entrada aún no veremos nada útil, pero sí una guía básica de algunas funciones muy usadas.
Cómo funciona un script
A poco que uno haya usado la consola de comandos, se da cuenta del patrón: escribo una orden, pulso [Enter], el intérprete de comandos ejecuta esa orden (cambiar de directorio, ejecutar un programa...) y, cuando termina, vuelve a quedar a la espera de nuevas órdenes.
Un script es sólo una serie de órdenes ya escritas, que se ejecutan una detrás de otra. Realmente, no es más que eso.
Por ejemplo, yo puedo escribir:
user:~$ touch ~/pacopepe -> Se crea el archivo "pacopepe" en mi directorio de usuario.
user:~$ mkdir ~/capreta -> Se crea la carpeta "capreta".
user:~$ mv ~/pacopepe ~/capreta/ -> Muevo el archivo dentro de la carpeta.
user:~$ echo "Jelou! Jaguar yu?" > ~/capreta/pacopepe -> Escribo ese texto dentro del archivo.
O puedo crear un archivo con estos comandos, ejecutar ese archivo desde la consola y que todo el proceso se haga de una sola vez:
#!/bin/bash
# -*- ENCODING: UTF-8 -*-
touch ~/pacopepe
mkdir ~/capreta
mv ~/pacopepe ~/capreta/
echo "Jelou! Jaguar yu?" > ~/capreta/pacopepe
user:~$ ./MiScript.sh
Cómo hacer un script
Primero, crear un archivo de texto plano, normal y corriente. Conviene, aunque no es obligatorio, usar la extensión ".sh"; por ejemplo "MiScript.sh". Al inicio del documento, pegamos esto:
#!/bin/bash
# -*- ENCODING: UTF-8 -*-
Es lo que se conoce como "shebang", y el sistema lo usa para reconocer un script y para saber cómo manejarlo. No es estrictamente imprescindible, pero evita muchos dolores de cabeza, sobre todo al usar el mismo script en otros sistemas.
La primera línea define qué intérprete de comandos deseamos usar. Bash es prácticamente universal en Linux y Unix, pero no olvidemos que no es el único, ni siquiera el original "estándar" (que sería Sh), y que no todos los intérpretes interpretan igual los comandos (valga la redundancia).
La segunda línea define la codificación de caracteres que se va a usar. Tampoco es imprescindible, pero ayuda a resolver problemas en caso de que falle por una codificación errónea. Hoy día, UTF-8 es prácticamente universal y soporta juegos de caracteres de cualquier idioma (tildes, diéresis, Ñ, Ç, etc...).
Ahora viene un paso que a mí siempre se me olvida: Hay que darle permisos de ejecución para que el intérprete de comandos pueda ejecutar las órdenes que contiene. De lo contrario, el sistema se negará a ejecutar nada.
En la mayoría de entornos gráficos, los permisos se pueden cambiar con facilidad accediendo a las propiedades del archivo desde el explorador; por ejemplo, en Nemo (el explorador de archivos por defecto en Cinnamon) es:
Click secundario del ratón -> "Propiedades" -> pestaña "Permisos" -> "Ejecutar:" -> Marcar la casilla "Permitir ejecutar el archivo como un programa".
En otros entornos suele ser muy parecido.
Desde consola también se puede hacer, claro:
chmod +x MiScript.sh
Y ya está, ya podemos empezar a meter código en nuestro script para que haga lo que esperamos. Parece engorroso, porque la explicación es un poco larga, pero en realidad es cuestión de segundos: Crear el archivo, copiarle el shebang y darle permisos de ejecución.
Cómo usar un script
Desde entorno gráfico: con doble click. Según cómo tengamos configurado el explorador de archivos, quizá se ejecute o quizá se abra con el editor de texto, pero lo normal es que nos pregunte cuál de las dos opciones usar.
Desde consola: A menos que copiemos el script en una carpeta definida en la variable $PATH (tema que no voy a tratar hoy), lo normal es que haya que escribir la ruta completa hasta el script:
./MiScript.sh (si estoy en la misma carpeta que el script)
o bien:
/home/usuario/MiScript.sh
o:
/una/ruta/cualquiera/MiScript.sh
A menudo, como cualquier programa de línea de comandos, los script pueden requerir parámetros: rutas, valores, nombres... Simplemente se ponen después de la ruta separados por espacios:
./MiScript.sh Paco 56
Veremos cómo trabajar con estos parámetros más adelante.
Qué encontraremos dentro de un script
Pues, sobre todo, comandos normales que hacen cosas normales: cambiar de directorio, mover un archivo, ejecutar un programa... También veremos operadores (+. -. =, <...), variables, saltos condicionales, bucles... Cosas que normalmente no usaríamos al trabajar directamente con la terminal, primero porque es un horror escribir estructuras complejas en una sola línea, y segundo porque, como estamos usando la consola "paso a paso", no necesitamos que el ordenador tome decisiones "inteligentes" durante el proceso.
Un par de ejemplos rápidos:
Variables
Definir una variable en bash es tan simple como esto:
variable1="Eufrasio"
Y usarla, normalmente, es tan sencillo como esto:
echo $variable1
Nota: Para evitar errores causados por espacios u otros caracteres que el intérprete pueda intentar interpretar como órdenes, es recomendable manejar las variables con cadenas de texto siempre entre comillas:
echo "$variable1"
Al ejecutar un script que incluyera estas líneas, veríamos como en consola aparece una línea con la palabra "Eufrasio".
Las variables pueden contener cadenas de texto (como en este ejemplo), números, rutas, comandos...
Condicionales
Un condicional siempre tiene la forma "Si tal condición es cierta, haz esto; si es falsa, haz esto otro". El ejemplo clásico es la secuencia "if - then - else", casi universal en el mundo de la programación, aunque cada lenguaje tiene su propia manera de escribirlo.
En Bash, un condicional típico sería algo así:
if [ "$variable1" == "Eufrasio" ]; then
echo "¡Hola, colega!"
else
echo "¿Tú quién eres?"
fi
Bucles
Un bucle es un bloque de código que se repite una y otra vez hasta que se cumpla una condición de salida. A veces, porque necesitamos hacer algo un número concreto de veces, como puede ser renombrar todos los archivos de una carpeta (P.Ej.: hay que repetir la acción de renombrar una vez por cada archivo; si hay 27 archivos, hay que ejecutar el mismo código 27 veces). Otras veces, porque algo debe estar haciéndose constantemente hasta que el usuario decida terminar (P.Ej.: Monitorizar la temperatura de la CPU cada 10 segundos, constantemente).
He aquí un pequeño ejemplo de bucle, de uno de mis scripts:
NumCores=4
i=0
cores="Pasos:"
while [[ $NumCores -gt $i ]]; do
((i++))
cores="$cores"" $i"
done
echo "$cores"
En este caso, el bucle empieza con $i=0, $NumCores=4 y $cores="Pasos: ". Al empezar, como $NumCores es mayor que $i, se cumple la condición ("-gt" es "greater than", esto es, "mayor que") y se ejecuta lo del interior: $i pasa a valer 1, y $cores se convierte en "Pasos: 1" ("1" es el valor de $i).
Al llegar al "done" se repite el ciclo: $NumCores sigue siendo mayor que $i, $i pasa a valer 2, y $cores pasa a contener "Pasos: 1 2".
Cuando $i llega a 4, $NumCores deja de ser mayor que $i y termina el bucle. Ya no se volverá a ejecutar lo que está entre el "while" y el "done", y continuará ejecutando lo que haya después... que en este caso es un "echo", que mostrará el contenido de $cores, "Pasos: 1 2 3 4".
Comentarios
Es buena práctica añadir texto explicativo dentro del propio script, texto de no debe ser interpretado por el sistema. En scripts Bash como éstos, los comentarios vienen precedidos del carácter #. Lo veremos mejor con un ejemplo:
# Si la variable contiene un nombre conocido, saluda:
if [ "$variable1" == "Eufrasio" ]; then
echo "¡Hola, colega!"
else
#Si no contiene un nombre, pregunta:
echo "¿Tú quién eres?"
# Ha faltado que añada "¿Tú quién eres, payaso?" XD
fi
Todo lo que venga precedido por # es ignorado por el intérprete de comandos.
Se usa también para evitar que se ejecuten líneas de comandos que no queremos usar ahora, pero tampoco eliminar del código. Por ejemplo, si estoy probando dos formas de hacer una tarea, puedo comentar todas las líneas de una de las maneras, probar la otra, y si me arrepiento sólo tengo que "descomentar" esas líneas.
Identación
¿Indenti qué?
La identación es esa manía que tenemos algunos de mover líneas a la derecha mediante espacios o tabuladores según profundizamos en estructuras complejas. En el ejemplo de antes, los comandos a ejecutar si el "if" es verdadero están identados un nivel, así como lo que se ejecuta tras el "else" en caso contrario.
En scripts muy sencillos parece innecesario, pero en scripts muy complejos ayuda a encontrar de un vistazo qué hará el script en cada caso.
Tengo scripts con 5 o 6 niveles de identación, con un "case" dentro de un "if", dentro de un "for", dentro de una función...
Esto es todo por ahora. En las próximas entradas iré trayendo y explicando algunos de los script que me he ido creando a lo largo de los años. Por ejemplo, tengo por ahí un viejo script que monta una imagen ISO de un juego en una unidad virtual, ejecuta el juego desde Wine y, cuando termina, desmonta la ISO de nuevo; la creé para no tener que estar peleando con los CD de mis viejos juegos de Windows. Tengo otro que baja la velocidad de la CPU cuando ésta pasa de determinada temperatura. Otro me permite tener el swap desactivado salvo que realmente haga falta. Y, por supuesto, el prometido launcher para Doom 3, que se ha complicado más de lo esperado... y ya pasa de las 700 líneas. XD
No hay comentarios:
Publicar un comentario