Las palomitas

No estamos hablando de metamorfosis. El maíz no es un capullo del que luego emerja una palomita. Siempre que comáis palomitas pensad que lo que estáis comiendo es un pequeño milagro: es la cristalización de un estallido. Una explosión puesta en pausa.
Berto Romero, Nadie Sabe Nada 5×38

Anuncios

Los captchas

Al principio te pedían que identificases señales y cosas así. Después era que identificases helicópteros… Lo próximo te va a poner una lista de gente y venga: identifica los terroristas afganos entre estos cinco.
Carlos González, Coffee Break Ep. 167

Shell-scripts: errores, señales y trampas

Aunque hace bastante que no preparo ningún script al que valga la pena hacer mención, he estado repasando algunas ideas sobre el tratamiento de errores. El scripting se parece mucho a programar, pero como todo lenguaje, tiene sus puntos fuertes y sus carencias. En particular voy a centrarme en cómo determinar el comportamiento de un script cuando se produce un error durante su ejecución, y como ayudarnos de unas pocas directivas para detectarlos y depurarlos.
Todo lo que viene a continuación está hecho con Bash en mente, así que funcionará tanto en MacOS como en GNU/Linux porque es la Shell más extendida, pero no lo he probado con otros terminales. Por cierto, ya que voy a utilizar las palabras “foo” y “bar“, no está de más aclarar que no tienen ningún significado, simplemente están ahí porque hay que poner un nombre y por convencionalismo.

Detener el script en caso de error
Imaginemos un script con el siguiente código:

Su salida es lo que uno espera. Un error alertándonos de que no existe ningún comando con el nombre “foo” y luego se imprime la palabra “bar”:

./script.sh: line 3: foo: command not found
bar

Aunque ha habido un error, el script ha continuado ejecutándose en la siguiente instrucción. Esto puede resultarnos peligroso o inadecuado para lo que estemos preparando, así que podemos utilizar la directiva “-e” para evitarlo:

Ahora sí, el guión se detiene en cuanto surge el error:

./script.sh: line 4: foo: command not found

He de aclarar que aunque la concatenación de instrucciones tiene implicaciones similares, abusar de ellas convertiría nuestro código en un churro intelegible; pero por si acaso:
foo & echo “bar”: Detecta el error y ejecuta la siguiente instrucción
foo && echo “bar”: Detiene el script cuando el comando devuelve error

La directiva -e no sólo rige los errores de comandos no válidos, sino que se aplica de forma más amplia a otros ejemplos de código, por ejemplo, a resultados de una operación que hayamos almacenado en una variable:

Produce:

ls: foobar: No such file or directory

Si de forma puntual necesitásemos esquivar el comportamiento marcado por esta directiva, podremos utilizar un pequeño truco de lógica:

El operador OR (||) con el segundo operando siendo “true” permitirá continuar la ejecución:

./script.sh: line 4: foo: command not found
bar

Y si nuestro comando fuese una condición de un bucle o de un “if”? Se evaluaría como falso, como por ejemplo aquí:

Se tomaría la rama del “else” y veríamos:

ls: foobar: No such file or directory
bar

Por lo tanto, la directiva -e puede ser de gran ayuda para evitar que nuestro script cometa errores… y que los arrastre durante el resto de su ejecución, que según lo que haga, puede terminar en resultados desastrosos. Pero aún hay más.


Detener el script si el error está en una tubería
No, no vamos a hablar de fontanería digital:

Cuando el error forma parte de una tubería de comandos, donde la salida del primero es la entrada del segundo, y así sucesivamente hasta el final de la tubería; el terminal simplemente indica el error y ejecuta el último comando de la tubería.
¡Ojo! No ejecuta los comandos que estén después del que da error; únicamente el último:

./script.sh: line 4: foo: command not found
a
bar

El problema entonces es que tenemos una tubería rota. Y una fuga. Y no hay nada peor que una fuga en una tubería rota. Eso es horrible. No quieres que eso suceda.
Para evitar que el problema vaya a más, tenemos otra directiva adicional (-o pipefail). Y digo adicional porque requiere que “-e” también esté presente para surtir efecto.

Si, se ejecuta el último comando de la tubería, pero la ejecución se detiene antes de continuar:

./script.sh: line 4: foo: command not found
a

Detener el script si hay variables no declaradas
Supongamos esto:

Nos arroja una línea en blanco porque la variable $a no está inicializada y luego imprime “bar” en la siguiente línea. Hasta aquí todo correcto. Pero si queremos evitar el uso de variables sin inicializar, usaremos la directiva -u:

Y con esto detenemos el script al llegar a ese punto de la ejecución:

./script.sh: line 4: a: unbound variable

Hay un truco que da un valor por defecto a una variable si no está inicializada o si está vacía, dependiendo del operador que utilices. Si quieres consultar más detalles sobre estos operadores, hay mucha información disponible sobre Expansión de Parámetros.
La opción “-u” está implementada de forma suficientemente inteligente como para ser tolerante en estos casos. Por ejemplo:

Digamos que como la variable VAR no estaba incivilizada, el operador “:-” le asigna el valor de la variable “default”. Por eso, la salida de estas líneas es:

5

Sin errores. Perfecto. Ahora veamos como aprovecharnos de esto para evaluar condiciones. El siguiente código se detiene porque la variable “mi_var” está sin inicializar y la directiva “-u” lo ha detectado:

Así lo muestra:

./script.sh: line 4: mi_var: unbound variable

Si queremos esquivarlo (y que el if pueda evaluar si mi_var está vacío o sin determinar, aprovecharemos ese operador:

Y obtenemos el mensaje:

mi_var no esta inicializada

No se detiene la ejecución por un error, ya que podemos evaluar la condición; pero conservamos la protección para no usar variables vacías más adelante. Lo puedes probar intentando mostrarla después por pantalla:

Te da:

mi_var no esta inicializada
./script.sh: line 10: mivar: unbound variable

Debug del código “por las bravas”
La opción “-x” permite imprimir por pantalla cada instrucción antes de que se ejecute. Si tienes un script con errores y todavía no los has localizado, tal vez te interese ir viendo paso a paso lo que sucede. Por ejemplo:

Tendrás:

+ a=5
+ echo 5
5
+ echo bar
bar

Simple, verdad?

Errores y trampas
De forma invisible, cada vez que hemos obtenido un error, el sistema recibe una señal ERR que podremos interceptar si queremos, mediante una trampa.
Una trampa no es más que un código que se ejecuta si se detecta la señal asociada. Algo así como una función de toda la vida, pero que en vez de ser disparada por una instrucción escrita por el programador, responde a la señal emitida por la máquina.

Bash (como otros lenguajes de programación) nos permite hacer esto de una forma bastante simple mediante la opción “-E” (en mayúscula). Por ejemplo:

Provoca:

./script.sh: line 5: foo: command not found
ERR detectado

En cuanto sale el error ERR, la trampa (“trap”) toma el control para ese tipo de señal y ejecuta la orden “echo ERR detectado”. Podríamos hacer una solución un poco más rebuscada, que mostrase el número de línea:

Que arroja:

./script.sh: line 6: foo: command not found
ERR detectado en 6

O incluso, creando un procedimiento algo más estilizado:

Que puede resultar muy práctico si utilizamos el procedimiento para imprimir los errores de diferentes trampas, con el numero de linea también como ayuda:

./script.sh: line 10: foo: command not found
*** ERROR DETECTADO
*** Error en la linea 10

Por último, si modificamos el mensaje donde informamos de la línea del error y cambiamos la variable $1 (donde hemos recibido el número de línea) por el resultado de la función “caller”:

Podemos también mostrar el archivo en el que se produjo el error:

./script.sh: line 10: foo: command not found
*** ERROR DETECTADO
*** Error en la linea 10 ./script.sh

Lo cual puede ser muy útil si el script consiste de varios ficheros.

#################################
Recursos:
https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
https://unix.stackexchange.com/questions/122845/using-a-b-for-variable-assignment-in-scripts/122878
https://unix.stackexchange.com/questions/39623/trap-err-and-echoing-the-error-line

La navaja

Nunca tuve en mi poder una navaja. Vaya usted a saber porqué a pesar de que desde pequeño siempre me han fascinado los personajes de las películas, libros y videojuegos de aventuras. Ese hombre (o esa mujer) resuelto, capaz de salir de cualquier apuro con una combinación de habilidad, conocimientos prácticos e ingenio. Podría mencionar a Indiana Jones, a Tintín, a Lara Croft… o a mis amigos. Personas cárnicas de cuerpo humano caliente.
Reconozco que son herramientas la mar de prácticas en mil y una situaciones; y cada vez que veía a alguien utilizarla, me venía el típico pensamiento “globo-chicle“. Una idea fugaz que surge en mi cabeza y que, tan pronto como aparece, explota y se va, desplazada por las cosas que realmente me ocupan, la conversación que estoy manteniendo, o una idea nueva con algo más de sustancia. ¿Por qué narices no tengo yo una también?

La navaja
El caso es que nunca tuve una pero hace algo más de un año, uno de mis mejores amigos se dejó una en mi casa y la enganché a mis llaves para recordar devolvérsela en cuanto tuviese ocasión.
Se trata de una Victorinox Classic SD en color azul, probablemente la navaja más común que existe y que podrías encontrar en casi cualquier parte.

Ésta en concreto, aunque pequeña, dispone de 7 herramientas básicas: tijeras, hoja de cuchillo, lima, destornillador, anilla, mondadientes y pinzas. No utilicé jamás el mondadientes por lo poco higiénico del asunto, pero las demás ya las he empleado todas.
Victorinox es sin duda la marca de navajas suizas por excelencia, tal y como puedes leer en la Wikipedia. Por eso no resulta difícil encontrarlas, incluso a través de Amazon. Otra marca bastante conocida y que me resulta familiar es Leatherman.

El día a día
Aquí van una lista hecha “al vuelo” de cosas mundanas que he llegado a hacer con la pequeña Victorinox:
– Abrir paquetes y cartas
– Cortar esos molestos pellejos de piel alrededor de las uñas
– Extraer astillas cuando me he clavado alguna
– Cortar y pelar cables, cuerdas y bridas
– Quitar las etiquetas a prendas de ropa nuevas
– Ayudarme de las pinzas para manipular tornillos muy pequeños
– Cortar fixo, cinta americana, aislante o de carrocero sin tener que recurrir a los dientes ni estropear más cantidad de la que iba a utilizar
– Abrir envases de comida rebeldes
– Pelar fruta
– Darle vueltas entre mis dedos (tengo las manos inquietas, pero cuidado con la hoja de corte)

El accidente
La situación donde tener la navaja fue determinante sucedió tal día como hoy el verano pasado. Volvíamos de una actuación y ya casi eran las siete de la mañana. En la furgoneta intentábamos no quedarnos dormidos volviendo desde A Cañiza hasta A Coruña; apenas había tráfico y todavía no habíamos pasado Santiago. A la altura más o menos de Padrón, nos encontramos un coche volcado unos pocos cientos de metros más adelante, tras una curva. Aquello nos despertó a todos de sobresalto.
Una mujer gateaba para salir por el hueco de la ventana de los asientos traseros, mientras un señor mayor hacía lo mismo desde la posición del conductor.
– ¡Os**as! ¡Frena! ¡Para ahí!
En apenas un par de segundos fuimos capaces de organizarnos: el conductor estaba llamando ya a los servicios de emergencias. Iba a poner triángulos y hacer señas a los otros vehículos que viniesen, para aminorar y tener precaución: cada vez que pasaba uno, minúsculos cristales y trozos de la carrocería del vehículo saltaban a una velocidad que los convertía en peligrosas cuchillas. El otro compañero, a ayudar al hombre; yo a la mujer. Todavía quedaba una señora en el asiento del copiloto, con el cinturón de seguridad aun puesto (gracias al cielo).
– ¡Emilio busca un cuchillo o un cúter en la furgo para cortar el cinturón!
La señora estaba sangrando por la cabeza y teníamos que sacarla de allí como fuese. Con la mujer sentada junto al quitamiedos, saqué la navaja de mi bolsillo y preparé la cuchilla. Ojalá pudiese cortar el cinturón. Por suerte, conseguimos cortarlo y sacar a aquella pobre señora.
Según el hombre relataba, no sabía lo que había pasado, podría haberse quedado dormido durante unas décimas de segundo. No dejaba de llorar, pedir perdón, clamar por que llegasen rápido las ambulancias e intentar que su mujer no perdiese el conocimiento. Estaban los tres desorientados, en shock. Les recuperamos sus pertenencias básicas. Había un par de teléfonos en el asfalto, llaves, una cartera, etc.
Con unas mantas, unas estructuras plegables de metal y unas espumas que llevábamos en la carga, pudimos hacer una especie de “tienda de campaña” improvisada donde refugiar a aquellas personas de la lluvia y calmarlas. Por suerte, las ambulancias y los bomberos llegaron rápidamente y nosotros continuamos nuestro camino más despiertos que nunca. Hoy en día (con el bonito recuerdo de haber podido ayudar a esta familia) nos reímos imaginando a los bomberos preguntándose al ver la situación: “¿Que rayos transportarán estos tres en esa furgoneta para haber montado este despliegue tan bizarro?” 😝

Otras Multi-herramientas
A raíz de todo lo que he utilizado la navaja desde que la tengo, me gustaría poder incluir también en mi mochila una Multi-tool (por ejemplo ésta, u otra similar). Además de las funciones de mi Victorinox, tienen muchos más usos. Como desventaja, son un poco más grandes y pesadas, con lo que no la utilizaría como llavero. Sin embargo, no está de más y no debería pesar en tu mochila o bandolera.

El regalo
Al volver a ver a mi amigo y contarle la historia con la intención de devolverle su navaja, directamente me dijo:
– Quédatela. Es útil y no tienes así que te la regalo. De todas maneras, yo necesito otra diferente.
Desde ese día, no me he separado nunca de ella. Aprendí la lección de que siempre hay que tener una navaja suiza a mano por lo que pueda pasar.

El inescrutable camino del monitor externo

Hace ya la friolera de diez años que decidí trabajar con una sola máquina. En aquel momento se trataba del Asus EeePC 901, un netbook con unas especificaciones nada fascinantes pero más que suficientes para usarlo cómodamente para mi trabajo diario, sobretodo cuando lo acompañé de algunos periféricos. Incluso cuando me actualicé al Asus EeePC 1215N, conseguí seguir trabajando de forma ágil gracias a un buen monitor, y un teclado y ratón inalámbricos.


Pero…
Al despedirme del netbook y cambiar a mi actual MacBook Pro con pantalla Retina, retiré el monitor de la mesa por dos motivos: la altísima densidad de píxeles de la pantalla del portátil (es decir, lo que Apple denomina “Retina”) y esa pulgada de más frente al 1215N, con la que el escritorio se me hacía bastante más espacioso. Cuando esto no era suficiente todavía me quedaba la posibilidad de utilizar resoluciones más altas (incluso las no soportadas por defecto en el sistema) y los escritorios múltiples.
Además, hay un pequeño inconveniente a la hora de usar MacOS con un monitor externo: si estás tirando de batería, no puedes evitar que el ordenador entre en reposo al cerrar la tapa. Lo cual es un fastidio porque tener el ordenador siempre enchufado a la corriente acaba por viciar y reducir la vida útil de la batería, lo mires como lo mires. De nada sirven las aplicaciones tipo Caffeine/Amphetamine para sortear este problema.

¿Adónde quiero ir a parar?
Bueno, no creo que sea casual que ahora que he vuelto a necesitar más espacio de trabajo, haya desempolvado el monitor externo. Sí, el mismo Acer P241W. Ya no tengo el Wireless Keyboard ni el Magic Mouse (y no pienso comprarlos de nuevo), así que estoy utilizando el viejo teclado extendido con cable de Apple y el ratón Tacens Mars Gaming MM0. El resto de periféricos alrededor del MacBook son también viejos conocidos de este blog: los altavoces, el dock para discos duros, una vieja impresora, un grabador de DVD externo…


La importancia del calibrado
Lo primero que pensé fue… ¡Dios! ¡Esto hay que calibrarlo! Recordaba que el monitor daba unos colores bastante aguados, pero es increíble lo mucho que hemos avanzado, no solo en resolución, sino en calidad de color, precisión, luminosidad, contraste… Lógicamente tomé la pantalla del MacBook como referencia y ajusté “a ojo” los colores, el contraste y el brillo para, al menos, sentirme un poco menos decepcionado. Y aunque lógicamente no ha quedado perfecto (en parte porque el panel TFT es el que es, y en parte porque no soy ningún experto), he conseguido unos colores bastante más razonables.
Los valores que estoy empleando pueden servir como referencia para futuros calibrados o incluso para alguien que tenga una pantalla como la mía (aunque me imagino que habrá diferencias en la calidad del panel incluso tratándose del mismo modelo). Básicamente:
- Contraste: 90%
- Brillo: 100%
- Rojo: 74%
- Verde: 72%
- Azul: 86%

Sensaciones
Volver a sentarme frente a un panel tan grande me trajo muy buenos recuerdos. Navegar vuelve a ser una experiencia muy inmersiva y los videos de Youtube siguen luciendo de maravilla. No quiero ni imaginarme si estuviésemos hablando de un monitor 5K como los que Apple vende para el nuevo MacBook Pro, o el interesantísimo LG 4K de 27 pulgadas al que @ipliomr está acechando.
La palabra que lo resume todo es comodidad. Comodidad cuando reproduces contenidos, o cuando simplemente puedes estar leyendo sin encorvarte sobre el portátil, o cuando tienes muchas más herramientas a la vista en la ventana de Office, Final Cut, etc. Hasta cierto punto es como volver a estrenar ordenador porque la experiencia es totalmente diferente a utilizar la pantalla integrada.

Entonces… ¿Porqué no un sobremesa?
Cabe preguntarse entonces porqué no volver al tradicional ordenador de escritorio, y aquí es donde tengo el corazón dividido.
Un sobremesa siempre te permite ir más allá en potencia y capacidad, además de estar menos expuesto a robos, caídas, pérdidas, etc.
Y si te ves obligado a saltar entre varios dispositivos, la nube te lo facilita con una gran flexibilidad. Apple pone además Handoff y Continuity a nuestra disposición, haciendo ese salto entre equipos aún más transparente, rápido y coherente. Incluso disfrutamos ya de Universal Clipboard, que es algo superpráctico.
El problema es que sigo convencido de que lo mejor es trabajar con una única máquina donde tengas centralizado todo tu trabajo y tu vida digital. En mi caso esa máquina es el portátil y no va a dejar de serlo debido a mi trabajo y a todas las cosas que hago en movilidad.
De hecho, actualmente mi único motivo para volver al PC en su sentido más clásico es poder montar una máquina dedicada a juegos y como repositorio de mi biblioteca de música, que en el portátil está ya agotando los últimos gigabytes de mi SSD.

La alternativa más sofisticada
Queda una opción algo rebuscada pero que permite seguir con todo centralizado y disponiendo de más potencia.
Empezamos montando un PC con hardware compatible con MacOS, es decir, un hackintosh. Instalamos Windows 10 y todos los juegos que queramos, y luego un Bootloader como Clover, por ejemplo.
Para jugar, bastaría con iniciar Windows 10 y listo, desde ahí es un paseo.
Pero ese bootloader y un cable Thunderbolt 2 enchufado al MacBook te dan una opción extra.
Encendiendo el Mac en modo disco de destino (pulsando la tecla T en el arranque) y utilizando su disco como disco de arranque del Hackintosh, tendrías una instalación de MacOS corriendo sobre el hardware que hayas montado, aun conservando todos los datos dentro del portátil, sin pasar por el aro de ninguna nube ni sincronización.
Es una alternativa muy sofisticada que no evita algún inconveniente (por ejemplo, la alimentación del ordenador portátil) pero permite que utilices tus flujos de trabajo habituales con la comodidad y la potencia del sobremesa, además darte acceso a ambos discos de forma simultánea.
No he probado esta solución (aunque espero poder hacerlo pronto) pero no veo ningún inconveniente que impida realizarla. Como se suele decir: seguiremos informando.