Bash
Comandos útiles
!!
Repite el último comando.!n
Repite el comando número n (dehistory
).!$
Último argumento del comando anterior.!:n
Argumento número n del comando anterior.
Combinaciones de teclas
Combinación de teclas | Acción |
---|---|
Ctrl + A | Ir al comienzo de la línea |
Ctrl+E | Ir al final de la línea |
Ctrl+F | Ir al siguiente carácter |
Ctrl+B | Ir al carácter anterior |
Alt+F | Ir a la siguiente palabra |
Alt+B | Ir a la palabra anterior |
Ctrl+L | Borrado de la pantalla |
Ctrl+R | Búsqueda en el histórico de comandos |
Ctrl+U | Borra el comando que se está escribiendo |
Programación en shell (con bash)
La shell es un intérprete de órdenes, que ejecuta dichas órdenes leídas de la entrada estándar o de un fichero, y que muestra los resultados por la salida estándar y la salida de error. Un programa escrito en shel no es más que un fichero de texto, pero con una peculiaridad: la primera línea; la primera línea del programa se encarga de decirle a la shel desde la cual ha sido llamado cómo debe ejecutar dicho programa. Para pedir que se ejecute bajo bash, esta primera línea debe ser:
#!/bin/bash
Variables y parámetros
Las variables se definen de la forma:
VARIABLE=[valor]
Si no se da un valor, se le asigna a la variable la cadena vacía. Cualquier valor que se dé será tratado como una cadena de caracteres. Para acceder al valor de la variable se hace:
${VARIABLE}
donde las llaves son opcionales. Los nombres de las variables suelen escribirse en minúsculas . También se suele poner entre comillas dobles (“ ”
) el valor de la variable.
Un programa escrito en shell puede requerir parámetros para su ejecución. Los parámetros en bash se referencian de la siguiente manera:
$0: éste es el nombre del programa.
$1: es el primer parámetro que se le pasa al programa en la línea de comandos. Los siguientes parámetros son $2
, $3
, etc. Si el número de parámetros es de más de un dígito, dicho número ha de escribirse entre llaves: ${12}.
$*: referencia todos los parámetros.
$#: referencia el número de parámetros pasados al programa (sin contar el nombre del mismo, $0
).
Estructuras
El bloque if
Tiene la forma:
if condición-1 then
lista-1
elif condición-2 then
lista-2
...
else
lista-n
fi
Una lista puede ser un comando o sucesión de comandos de la shell, llamadas a programas externos, etc. Los elementos entre corchetes son opcionales.
A continuación se ve un primer ejemplo de programación en bash. La primera línea indica que se debe interpretar con bash. En la línea siguiente se ve el carácter ‘#’ indicando que se trata de un comentario. El resto del código pertenece a un bloque if. El corchete ‘[‘ es el comando test que comprueba la condición que se le pasa como parámetro. El comando source lee y ejecuta las órdenes contenidas en el fichero que se le pasa como parámetro, y devuelve el código de retorno resultante de la ejecución de la última orden contenida en dicho fichero.
#!/bin/bash
# Este programa busca ficheros de configuración en
# sus directorios habituales, y los ejecuta si existen.
if [ -f \$HOME/.bash_profile ]; then
source $HOME/.profile
elif [ -f i/etc/profile ]; then
source /etc/profile
else
echo "No hay ficheros de configuración"
fi
El bloque case
Permite comparar una palabra con una serie de patrones, y especificar las acciones correspondientes en el caso de que la expresión coincida con alguno de los patrones. La sintaxis es la siguiente:
case $variable-name in
pattern1|pattern2|pattern3)
lista-1
;;
pattern4|pattern5|pattern6)
lista-2
;;
pattern7|pattern8|patternN)
lista-n
;;
*)
esac
Una palabra (o token) es, para la shell, una secuencia de caracteres considerada como un bloque.
Ejemplos de scripts
Nota:
Prácticamente todos los scripts funcionarían con otro shell, aunque bash es el más utilizado, si dicen que se haga con sh o con ksh, sólo habría que cambiar la primera línea #!/bin/bash
por #!/bin/sh
o #!/bin/ksh
. Entre ellos cambia la sintaxis, pero muy poco. Si no dicen nada se puede dejar bash
Ejemplo fechas y crontab
Queremos conocer la ocupación del sistema de ficheros /usr
cada hora. Para ello se pide guardarla en un fichero.
-
Se crea un script para guardar esa información en un fichero (
/usr/local/bin/ocupacion_usr.sh
):#!/bin/bash FECHA=`date +%Y-%m-%d:%H:%M` OCUPACION=`du -sh /usr | awk '{print $1}'` # du -sh /usr -> muestra lo que ocupa el directorio /usr # -s : tiene en cuenta también lo que ocupan los subdirectorios # -h : en modo "humano", lo muestra en megas no en ks # awk '{print $1}': muestra la primera columna del texto que se le envía # el du devuelve algo del tipo: "400M /usr". Así que con el awk obtenemos "400M" echo $FECHA $OCUPACION >> /tmp/ocupacion_usr.txt # escribe la fecha con el formato año-mes-día:hora:minutos y el tamaño ocupado # todo ello lo copia en el fichero /tmp/ocupacion_usr.txt # con >> se indica que lo añada al fichero (si fuera > lo sobreescribiría)
-
Se hace el script ejecutable:
chmod +x /usr/local/bin/ocupacion_usr.sh
-
Ahora se hace que este script se ejecute cada hora, para ello se utiliza crontab:
crontab -e
y aquí escribimos:
0 * * * * /usr/local/bin/ocupacion_usr.sh
Nota
La sintaxis de crontab es la siguiente:
- minutos (0: se ejecutará cada vez que el minuto sea 0)
- hora (*: se ejecutará a todas las horas)
- día mes (*: se ejecutará todos los días)
- mes (*: se ejecutará todos los meses)
- día semana (*: se ejecutará todos los días de la semana)
- qué ejecutar: el script que hemos creado
si por ejemplo se quisiera que se ejecutar todos los martes de enero y febrero a las 5h15 se haría:
15 5 * 1,2 2 /usr/local/bin/ocupacion_usr.sh
y si fuera de enero a mayo:
15 5 * 1-5 2 /usr/local/bin/ocupacion_usr.sh
Ejemplo memoria libre y correo
Queremos que cuando la memoria libre sea menor de 10 MB nos envíe un correo.
Sabemos que el comando free devuelve el tamaño de la memoria en el siguiente formato:
> free -m
total used free shared buff/cache available
Mem: 501 220 18 21 262 165
Swap: 2047 162 1885
En este caso hay 18MB libres.
- Ejecutamos el siguiente script:
#!/bin/bash
while [ true ] ; # se estará ejecutando indefinidamente
do
mem=`free -m |awk 'NR==2 {print $4}'`
# free -> da la memoria libre del sistema
# -m : en megas
# awk -> extrae texto
# NR==2 : la 2ª línea
# {print $4}: la 4ª columna
if [ $mem -lt 10 ]; # Cuando sea menor de 10
then
echo "La memoria libre es menor de 10MB" | /bin/mail -s "ERROR MEMORIA" sarita@correo.com
fi
sleep 5 # Esperamos 5 segundos, antes de la siguiente ejecución del bucle
done # fin while
Notas
- La ejecución se pararía con Control-C
- Se podría hacer con un crontab como el anterior.
Loggin en scripts bash
Técnicas Comunes de Logging en Scripts Bash
-
Registro Básico en un Archivo: La forma más sencilla de registrar información en un script Bash es redirigiendo la salida estándar (stdout) y la salida de error (stderr) a un archivo de log utilizando operadores de redirección. Esto permite capturar tanto mensajes informativos como errores en un archivo específico para su posterior análisis.
#!/bin/bash # Ubicación del archivo de log LOG_FILE="/var/log/miscript.log" # Función de registro function log_message() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE" } # Uso de ejemplo log_message "Inicio del script." # Simulación de una tarea if -d "/algún/directorio" ; then log_message "El directorio existe." else log_message "El directorio no existe." fi log_message "Fin del script."
En este ejemplo, se define una función
log_message
que añade una entrada al archivo de log con una marca de tiempo y el mensaje proporcionado. Esta técnica es útil para realizar un seguimiento cronológico de las acciones del script y facilita la identificación de problemas o el monitoreo de su comportamiento. -
Uso de
logger
para Registrar ensyslog
: El comandologger
permite enviar mensajes al sistema de registrosyslog
, que es el servicio de registro estándar en sistemas Unix y Linux. Esto es especialmente útil para centralizar registros y aprovechar las facilidades de gestión que ofrecesyslog
.#!/bin/bash # Función de registro utilizando logger function log_message() { logger -t "miscript" "$1" } # Uso de ejemplo log_message "Inicio del script." # ... log_message "Fin del script."
En este caso, los mensajes se envían al sistema
syslog
con una etiqueta (-t
) que identifica el origen del mensaje, facilitando su filtrado y análisis en entornos con múltiples fuentes de log. -
Redirección de Salida y Errores: Otra técnica común es redirigir tanto la salida estándar como la de error de todo el script a un archivo de log. Esto se puede lograr al invocar el script de la siguiente manera:
./miscript.sh > /var/log/miscript.log 2>&1
Aquí,
>
redirige la salida estándar al archivomiscript.log
, y2>&1
asegura que la salida de error se combine con la salida estándar, de modo que ambos tipos de mensajes se registren en el mismo archivo.
Buenas Prácticas en el Logging de Scripts Bash
Para optimizar el uso de logs en scripts Bash, se recomienda seguir ciertas buenas prácticas:
-
Definir Objetivos Claros de Logging: Antes de implementar registros, es fundamental establecer qué información es relevante capturar y con qué propósito, ya sea para depuración, monitoreo o auditoría.
-
Utilizar Niveles de Log Adecuados: Clasificar los mensajes de log según su importancia facilita la gestión y el análisis. Los niveles comunes incluyen DEBUG (para información detallada de depuración), INFO (para eventos informativos generales), WARN (para advertencias sobre posibles problemas) y ERROR (para errores que requieren atención).
-
Implementar Logs Estructurados: Registrar la información en un formato estructurado, como JSON, permite una mejor parsificación y análisis automatizado de los logs, facilitando su integración con sistemas de monitoreo y análisis.
-
Evitar Registrar Información Sensible: Es crucial no incluir datos confidenciales, como contraseñas o información personal, en los logs para mantener la seguridad y cumplir con regulaciones de privacidad.
-
Gestionar la Retención y Rotación de Logs: Implementar políticas de rotación y retención de logs ayuda a controlar el uso del espacio en disco y asegura que los registros relevantes estén disponibles durante el tiempo necesario para análisis o auditorías.
Al seguir estas prácticas y técnicas, se mejora la eficiencia y eficacia del logging en scripts Bash, contribuyendo a sistemas más robustos y mantenibles.
Bibliografía
- Ramón Fernández Marina.
Programación en Shell (Linux Actual 1)
. Prensa Técnica, 1998 - Néstor Lucas.
Linux Actual 6
. Prensa Técnica, 1998 - Brian P. Hogan.
Small, Sharp Software Tools: Harness the Combinatoric Power of Command-Line Tools and Utilities
. Pragmatic Bookshelf, 2019