Mostrando entradas con la etiqueta Bash. Mostrar todas las entradas
Mostrando entradas con la etiqueta Bash. Mostrar todas las entradas

martes, 13 de septiembre de 2022

Buenas practicas Shell Script

Ahí van un compendio de buenas prácticas, bastante sencillas de aplicar, pero que de no estar haciendolo ya, pueden marcar una gran diferencia en la calidad de tus scripts...

¿Que shebang?... #!/usr/bin/env bash  Vs #!/bin/bash

Si hablamos de flexibilidad es preferible usar #!/usr/bin/env bash , dado que no requiere que el sistema tenga bash en /bin, solo que este en el path del usuario, si por el contrario hablamos de seguridad, es preferible #!/bin/bash dado que un usuario no podría tener un bash distinto al del sistema.

Mejor opción larga... --output vs -o

Siempre que sea posible y por temas de mantenimiento de código, es preferible usar la opción más legible para la mayoría, por lo que usaremos la opción "larga"

Cabecera de control.

Como norma es recomendable proveer a nuestro script de ciertos controles o salvaguardas, para evitar comportamientos no deseados. Un buen punto de partida puede ser este aunque puede ajustarse según preferencias.

set -o errexit # abort on nonzero exitstatus
set -o nounset # abort on undeclared variable
set -o pipefail # don't hide errors within pipes
# set -o xtrace # track what is running - debugging

Con esto evitamos que el script siga ante:

  • errores de alguno de los comandos., si definimos esto en el shebang en caso de forzar la ejecución bash xxx.sh , no se aplicará, por lo que se recomienda usar set
  • variables no declaradas, salvo que se indique lo contrario explícitamente. (Más adelante)
  • Salida detallada de los errores

Con la ultima opcion podemos activar la traza de ejecución para debbugear errores.

Variables

  • Siempre debemos definir las variables como ${var} y no como $var
  • Las variables que pueden contener space: deben usar "", de modo que ${var} sería "${var}"
  • Usaremos "${var}" dentro de una comparación, para evitar errores de sintaxis con variables no definidas.
  • Variables globales de solo lectura con el comando readonly: readonly mivariable = "/opt/mipath/mifile.sh"

Capitalización:

  • Variables de entorno en mayúsculas (exportadas): ${ALL_CAPS}
  • Variables locales del script en minúsculas: ${lower_case}

Sustitución de comandos:

  • Usar $(command) antes que `command`

lunes, 21 de septiembre de 2015

Raspberry + Telegram

Este post, solo pretende ser unas simples notas sobre la instalación y uso del cliente de Telegram.
Aplicación de mandar avisos al teléfono…. las 1000 y una Frikadas…. que cada uno decida las suyas.

Instalación

apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev make python2.7-dev libevent-dev libjansson-dev
cd /opt
git clone --recursive https://github.com/vysheng/tg.git && cd tg
./configure
make

En varios sites he visto que no usan el «recursive», sin esta tendremos cabeceras no resueltas, cuando intentes compilar.

Arrancar el cliente.

Tras esto podemos arrancar la app (Hace uso de algun path relativo por lo que debes entrar en «/opt/tg» aunque la invoque con el path absoluto):

/opt/tg/bin/telegram-cli -k tg-server.pub -W

Nota: La primera vez te dara un codigo que deberas introducir en la app de tu teléfono.
Puedes revisar la lista de comando con «help»

Comandos interesantes.

Un par de comando que he usado:

contact_list (Lista tus contactos.)

NOTA: Con el cliente arrancado puedes tabular para completar, lo cual te permite completar, por ejemplo, el nombre de un contacto y darte cuenta que si tienes espacios para la app son «_» de modo que:
contacto con espacio es contacto_con_espacio y no "contacto con espacio"

Mandar msg y ficheros de texto.

Para mandar msg, basta con teclear con el cliente arrancado…

msg Contacto "Texto a enviar"

Si queremos mandar el contenido de un fichero de texto.

send_text Contacto /ruta/fichero

Nota: Para mandar un msg a alguien por primera vez es necesario crear el chat antes:

chat_add_user Nobre_Chat Contacto

Tras esto podemos mandar el msg con el comando «msg»
Hasta aqui el uso del cliente pero y en un script como…..

Envio del contenido de un fichero de Texto.

Este script «/usr/loca/tg_text.sh» recibe dos argumentos, arranca el cliente y manda el msg (Fichero de texto).

#!/bin/bash
destination=$1;
text=$2;
(sleep 10;echo "send_text $destination $text"; sleep 5; echo "safe_quit") | /opt/tg/bin/telegram-cli -k tg-server.pub -W

Invocamos con: (Recordar…. dentro de «/opt/tg»)

/usr/local/tg_text.sh Usuario /usr/local/fich.txt

Envio de un msg.

Este script es idéntico al anterior pero cambiamos el comando send_text por msg.

#!/bin/bash
destination=$1;
message=$2;
(sleep 10;echo "msg $destination $message"; sleep 5; echo "safe_quit") | /opt/tg/bin/telegram-cli -k tg-server.pub -W

Invocamos con: (Recordar…. dentro de «/opt/tg»)

/usr/local/tg_msg.sh Usuario "Texto a enviar"

Aplicaciones…. lo dicho, muchas por ejemplo, parsear periódicamente webs de descargas y recibir las novedades en el móvil…..

Lo próximo una cámara un sensor de movimiento y….. el gato como actor principal xDDD

sábado, 19 de julio de 2014

Apagado disco USB – RaspBerry

Publicación original: 19.07.2014

Tengo una raspberry conectada 24/7, en la cual tengo conectado un disco usb que uso muy poco (motivo por el que nunca se me había planteado la necesidad de poder «apagarlo» automáticamente). Hasta ahora montaba y desmontaba el disco según necesidades.

Es posible que para un proyecto futuro, me interese tener el/los disco/s montados siempre y que el SO los apague según el tiempo de inactividad.
Un compañero me comento el uso y me he puesto a mirar HDPARM

Nota:

Simplemente a modo de recordatorio, buscando info sobre el tema he visto que podemos saber si ha existido actividad en el disco consultando el fichero:

/sys/block/sda/stat

Cuando se realizan operaciones sobre el disco el valor número cambia.

cat /sys/block/sda/stat | tr -dc "[:digit:]"

HDPARM

Con mi disco he tenido unos problemas, que detallare al final. Aunque el estado «unknown» que se ve a continuación, esta relacionado con mis problemas.

Ver el estado del disco:

root@RASP1:~# hdparm -C /dev/sda1
/dev/sda1:
drive state is: unknown
root@RASP1:~#

Si todo funciona correctamente el estado debe ser «active/idle, standby»….

Ver el tiempo tras el que pasaremos a inactividad «spin-down«

root@RASP1:~# hdparm -B /dev/sda
/dev/sda:
APM_level = 120

Este valor se debe entender del siguiente modo:
  • SI Permitimos el Spin-Down: Entre 1 y 127
  • NO Permitimos el Spin-Down: Entre 128 y 254
  • El valor de 255 : Desactiva la gestión de energía avanzada del disco duro.

Cuando permitimos el spin-down, el tiempo en segundos, se obtiene multiplicando por 5 el valor dado, así un valor de 120, serán 120*5 segundos….. 10 minutos

Estableciendo el valor:

Para esto editamos el fichero de configuración de hdparm:

/etc/hdparm.conf

Y al final añadimos: (Este punto no he conseguido que funcione con mi disco)

/dev/DISCO {
  spindown_time = Valor_deseado}
Tras esto es suficiente con dejar el demonio corriendo:

/etc/init.d/hdparm restart

NOTA: Problemas con mi disco

Las pruebas las estoy haciendo con un disco WD:


root@RASP1:~# hdparm -I /dev/sda
/dev/sda:
ATA device, with non-removable media
Model Number: WDC WD5000BEVT-11A03T0
Serial Number: WD-WX30A6957814
Firmware Revision: 01.01A01
...

En este disco no he podido definir el valor en el fichero de configuración, así como ver el estado del disco, ni forzar el «apagado» del disco


root@RASP1:~# hdparm -y /dev/sda
/dev/sda:
issuing standby command
HDIO_DRIVE_CMD(standby) failed: Invalid argument

Sin embargo el disco si para cuando establezco el valor via comando:

root@RASP1:~# hdparm -B 121 /dev/sda
/dev/sda:
setting Advanced Power Management level to 0x79 (121)
HDIO_DRIVE_CMD failed: Invalid argument
APM_level = 121
root@RASP1:~# hdparm -B /dev/sda
/dev/sda:
APM_level = 121
root@RASP1:~#
root@RASP1:~#
root@RASP1:~# hdparm -B 120 /dev/sda
/dev/sda:
setting Advanced Power Management level to 0x78 (120)
HDIO_DRIVE_CMD failed: Invalid argument
APM_level = 120
root@RASP1:~# hdparm -B /dev/sda
/dev/sda:
APM_level = 120

Este valor esta en uso hasta que el disco se desconecta de la corriente. Por lo que no es un problema para mi no poder, establecerlo de manera permanente.

lunes, 14 de julio de 2014

Procesos en segundo plano – SIGHUP, NOHUP

Publicación original: 14.07.2014

Me parece interesante a modo de «chuleta» y/o recordatorio comentar un poco este tema…
Lo quiero separar en dos partes una sobre los procesos en segundo plano y otra sobre la señal SIGHUP.
  • Procesos en segundo plano
Los procesos en segundo plano son aquellos que pese a estar en ejecución no tenemos la posibilidad de interactuar con ellos.

La manera de lanzar procesos en segundo plano es añadiendo al final , de este modo el proceso quedará en ejecución pero liberará la shell, para poder seguir trabajando.

gandalf ~ # find / -name hola &
[1] 19968
gandalf ~ # ps -ef|grep find
...
[1]+  Hecho                   find / -name hola

Para poder interactuar con estos procesos necesitamos traerlos a primer plano y para realizar esta gestión tenemos los comandos jobsbg y fg

Un ejemplo…. Lanzamos dos procesos en segundo plano:

gandalf ~ # while true; do echo "ab" > /dev/null; done &
[1] 20265
gandalf ~ # while true; do echo "a" > /dev/null; done &
[2] 20266

Visualizamos los procesos en segundo plano así como su estado:

gandalf ~ # jobs
[1]-  Ejecutando              while true; do
echo "ab" > /dev/null;
done &
[2]+  Ejecutando              while true; do
echo "a" > /dev/null;
done &

Traemos uno de los procesos a primer plano y lo detenemos con Ctrl+Z

gandalf ~ # fg %1while true; do
echo "ab" > /dev/null;
done
^Z
[1]+  Detenido                while true; do
echo "ab" > /dev/null;
done

Al listar los procesos en segundo plano tenemos uno detenido y uno en ejecución.

gandalf ~ # jobs
[1]+  Detenido                while true; do
echo "ab" > /dev/null;
done
[2]-  Ejecutando              while true; do
echo "a" > /dev/null;
done &

Volvemos a poner en ejecución en background el proceso que estaba detenido.

gandalf ~ # bg %1
[1]+ while true; do
echo "ab" > /dev/null;
done &
gandalf ~ # jobs
[1]-  Ejecutando              while true; do
echo "ab" > /dev/null;
done &
[2]+  Ejecutando              while true; do
echo "a" > /dev/null;
done &

También podemos matar un proceso en background determinado

kill %2



  • SIGHUP / NOHUP
Cuando un proceso termina lanza una señal SIGHUP a los procesos que cuelgan de el, y estos reaccionan simplemente saliendo.
Esto es un problema cuando queremos dejar corriendo algún proceso en la shell en la que nos encontremos, ya que aun teniéndolos en background, al salir de la shell el proceso terminará.
Podemos evitar esto lanzado el proceso con NOHUP, lo cual hará que el proceso no «escuche» la señal SIGHUP de su proceso padre.
Para lanzar un proceso con NOHUP basta con (nohup «comando»), por ejemplo:

nohup ./script.sh arg1 arg2
nohup su - user -c "./script arg1 arg2"

Algo interesante, a tener en cuenta, es el tratamiento de la salida /entrada estandar, así como de la salida de error que hace nohup.

  • Salida estandar –> Si no esta redirigida, se redirige a $HOME/nohup.out
  • Entrada estandar –> SI no esta definida toma valor de «/dev/null»
  • Salida de error –-> Si no está definida es redirigida a la salida estandar.

domingo, 4 de mayo de 2014

Referencia Indirecta - Bash

Este post es más una nota que un post como tal, por su extensión y sobre todo por su función.....

Hace un par de semanas necesité hacer uso del concepto de punteros en bash.
La verdad es que no se si lo había usado anteriormente, lo que si sé, es que no recordaba como hacerlo, de ahí esta nota.

El concepto se llama habitualmente referencia indirecta.

Simplemente pretendo dejar plasmada la sintaxis a modo de recordatorio, así que no me extenderé nada.....

Podemos referenciar variables de dos modos... directa o indirectamente.

Antes de BASH v.2
A="cadena resultante"
B="A"
-------------------------
echo $A
.......cadena resultante
-------------------------
echo $B
.......A
-------------------------
eval C=\$$B
echo $C
.......cadena resultante


Desde BASH v.2
A="cadena resultante"
B="A"
-------------------------
echo $A
.......cadena resultante
-------------------------
echo $B
.......A
-------------------------
echo ${!B}
.......cadena resultante

Podemos acceder al contenido de la variable A, haciendo uso de su propia referencia o de la referencia que contiene la variable B.

La referencia la obtuve del siguiente artículo.
Aquí un artículo donde se detalla perfectamente este concepto.