Primeras horas usando MacOS Mojave

La pasada noche pude por fin hacer la instalación limpia de MacOS 10.14 (que ya iba siendo más que necesaria) y las sensaciones por ahora están siendo muy buenas. Todo funciona como uno espera de un sistema operativo veterano y construido sobre unos sólidos cimientos, pero por fin (desde Yosemite) estoy aprovechando las novedades que trae para el común de los mortales.

Las notas de voz por fin se sincronizan
No me explico como Apple pudo haber tardado tanto en meter sincronización por iCloud a iMessage. Y lo mismo sucedía con las Notas de voz. Esta novedad me viene de perlas porque las uso bastante, además de las tradicionales notas de texto; y poder pivotar entre dispositivos sin pasar por el peaje de iTunes es todo un acierto.
Como punto negativo, la iOSificación de macOS ya es más que evidente. “Notas de voz”, “Bolsa” o “Casa” son simples ports de las versiones móviles y se echa en falta, por ejemplo, poder importar ficheros de audio como nota de voz.

El modo oscuro y los fondos dinámicos
Visualmente es lo más llamativo (por no decir lo único) de esta versión. Estará por ver si consigue tracción suficiente para que aplicaciones de terceros (tipo Office) o algunas páginas web (por ejemplo Facebook) se sumen al carro.
¡Por favor! ¡Más fondos dinámicos! Hay algo hipnótico en ellos conforme pasan las horas ante el monitor.

Pilas en el escritorio
La organización por pilas es eficaz y permite poner orden hasta en el más caótico escritorio. Es una idea útil, concreta y sencilla que se ha llevado a cabo de forma eficiente y bella. Probablemente “lo más OS X” que se ha implementado en macOS desde hace años.

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

Estás minando criptomonedas sin saberlo?


Empieza a ser preocupante con el auge de las criptodivisas (Bitcoin, Monero, etc.) que la avaricia de algunos webmasters esté pasando factura a los ordenadores de sus visitantes. Yo venía notando una carga de trabajo elevada en el portátil últimamente, cada vez que veía alguna serie online.

Es cierto que, por un lado, recurro a un sitio donde puedo verlas gratuitamente; pero lo rápido que se drenaba la batería en segundo plano y los (cada vez más) frecuentes avisos de Safari sobre una página que se había recargado por consumir muchos recursos llegaron a preocuparme. ¿Era un problema mío? ¿O había algún factor externo que provocaba estos síntomas?

Tampoco puedo negar que llevaba un tiempo navegando como si fuese Superman o algo así: ni antivirus, ni bloqueador de publicidad, ni nada de nada. A pelo. Como un superhéroe de The Defenders. Como un inconsciente. Fue poner un bloqueador en Safari (concretamente AdGuard) y mis sospechas se confirmaron de inmediato como podéis ver en la imagen que encabeza el post.

En definitiva, Internet es cada día un lugar más salvaje, donde cada bit y cada megahertzio que pueda ser explotado, será explotado. Y ahora ya no se trata de poner publicidad porno pagada a precio de perfumería cara. Ni de colarte programas con licencia shareware de 15 o 30 días. Ni de que te suscribas a otra newsletter. Ni de que te instales una app en tu móvil.
El Internet del lejano oeste en el que nos toca vivir estos días está plagado de redes sociales que ya han recolectado mucha información sobre ti antes incluso de que te registres. De servicios y aplicaciones que monitorizan en qué empleas tu tiempo, qué comes, qué ves en la tv, qué compras, qué sitios visitas. De auténticos delincuentes que te graban con tu propia webcam (y a veces ni eso) o que cifran tu disco duro para luego extorsionarte. Y de gente que te cuela un pequeño e ilegible trozo de Javascript para poner tu máquina a su servicio. Y dios sabe qué más.

No quiero registrarme en tu servicio


Ya he escrito en algún que otro post que estoy muy cansado de ir teniendo cuentas abiertas por ahí en servicios de cualquier tipo. He conseguido cerrar cuentas en cosas como Spotify, Mega, Dropbox, etc. porque he encontrado buenos reemplazos para este tipo de software.
Y la verdad es que también me gustaría poder cerrar mi cuenta de Feedly y tan sólo emplear un lector sencillo en mi Mac.

No me entiendas mal: Feedly como servicio en sí mismo está más que bien, funciona como un reloj y tengo bastantes artículos guardados “para leer después”, que es un eufemismo demasiado optimista para “el titulo tiene buena pinta, pero no tengo tiempo para leerlo ahora y no voy a tenerlo nunca”. O al menos en mi caso.
Y como apenas sigo a un par de personas en Twitter (cuenta que también me gustaría cerrar más pronto que tarde) y estas cuentas solo las sigo porque me interesan noticias muy específicas, comencé a darle vueltas a una idea: un lector RSS en el que también pudiese seguir a usuarios de Twitter.

Feedly puede hacerlo: tan solo has de obtener el feed del usuario en cuestión y puedes sacar la url con servicios como TwitRSS
Pero cuando se trata de Apps… incluso las que no sincronizan con nada ni nadie… todas quieren que te registres. Todas necesitan un login y un password. Algunas incluso que inicies sesión con una cuenta de… lo has adivinado: Feedly! La competencia!! Esto es insólito.
He leído recomendaciones de programas de pago (y no me disgusta la idea de pagar un precio justo por una buena pieza de software) pero en general las opciones que he visto hasta el momento son muy poco simpáticas. Y esa obsesión por obtener datos de tus usuarios… a estas alturas cualquier cuadro de diálogo para entrar a un servicio ya me repugna. ¿Alguna sugerencia? Por favor, déjamela en los comentarios. Ah! Creo que debes registrarte para comentar… 😡