martes, 15 de diciembre de 2015

Manejo del portapapeles desde la línea de comandos

El portapapeles está muy bien para copiar y pegar texto con el ratón, pero a veces nos puede interesar manipularlo de forma no interactiva, desde la línea de comandos o desde nuestros scripts.

Dos comandos especialmente populares en el mundo Mac permiten esto: pbcopy y pbpaste. Las iniciales "pb" significan "pasteboard", que es como llaman al portapapeles en los Mac, mientras que en Linux y Windows suele usarse más el término "clipboard", aunque en el fondo esto es cuestión de caprichos.

Aunque pbcopy y pbpaste sean los más famosos, los otros sistemas operativos también tienen comandos que podemos utilizar para lograr lo mismo. En Windows, tenemos el comando clip.exe (aunque me parece que sólo funciona para copiar, pero el pegado ha de ser interactivo). 



En Linux tenemos bastantes más opciones, mi elección ha sido el comando xsel. No viene en la distribución estándar, pero se instala fácilmente con 

$ sudo apt-get install xsel 

Si investigais un poco encontraréis otras herramientas (xclip...), con multitud de opciones.

De todas formas, tan populares se han hecho los nombres originales del mundo Mac que yo he optado por seguir el consejo que dan en muchas páginas web: hacer un alias para esos comandos. Para ello, en el fichero de configuración $HOME/.basrc no hay más que añadir estas dos líneas:

alias pbcopy='xsel --clipboard --input'
alias pbpaste='xsel --clipboard --output'

Aquí podéis ver un ejemplo para copiar un calendario al portapeles desde la línea de comandos y pegarlo luego tanto en la línea de comandos como en un editor de texto:


Para sacarle partido a fondo, ya se sabe:

$ man xsel | less
 
Ale, a copiar y pegar y copiar y pegar y copiar y pegar.

miércoles, 2 de diciembre de 2015

Visto y no visto: una parte ocultable en una página web

Los usuarios, esas ricuras

Me encantan los usuarios contradictorios. Al fin y al cabo, esas contradicciones no dejan de reflejar la naturaleza humana, así que no hay por qué asustarse. Hay que saber escucharlos, y darles lo que realmente quieren o necesitan, que muchas veces no coincide exactamente con LO QUE TE PIDEN.

En esta ocasión, por un lado me piden que les incluya un texto fijo en una página web, unas instrucciones que deben ser utilizadas y tenidas en cuenta por todos los que utilizan la página. A veces la aplicación web les devuelve determinados resultados y los usuarios tienen que consultar en la documentación en papel, unas normas complejas que en los últimos meses están cambiando bastante (dependen de unas leyes un tanto "inestables"). Tener la información a la vista en la página, mientras usan el programa, les evitaría tener que abandonar la página para sumergirse en los papeles.

Pero, por otro lado, tener delante el texto, todo el tiempo, les molesta. Funcionalmente, no aporta utilidad al programa. No se necesita consultar siempre, sólo si el programa devuelve determinados datos, para dar explicaciones, para realizar procesos manuales... Así que, mientras unos me piden que el texto esté a la vista, otros me pregunta si no se puede quitar, ya que les "ensucia" la página.

O sea, resumiendo, quieren que las instrucciones se vean, pero al mismo tiempo, no se vean. Qué ricos.

Fig. 1. Que se vea, pero que no se vea. 
Foto: Jorge A. Loffler, Flickr, licencia CC BY-SA 2.0

Texto ocultable

Para resolver esto se pueden dar muchas soluciones, y seguro que los especialistas en interacción persona-ordenador lo han estudiado hasta la saciedad. El tema de dónde ubicar un elemento en la interfaz de usuario no es algo para tomarse a la ligera, sobre todo en aplicaciones que tengan cierta repercusión, con un alto número de usuarios. 

Una opción sencilla sería poner las instrucciones en una página aparte, y en la página principal poner un enlace, que se abra en una nueva ventana o pestaña. Sin embargo, en esta ocasión, yo me voy a limitar a una solución también muy simple y bastante efectiva, a juzgar por el feedback que me han dado los usuarios.

La técnica consiste en comenzar con el texto oculto en la página, y un botón que permita visualizarlo o volver a ocultarlo a placer. También se podía haber hecho justo al contrario: empezar con el texto visible, y que el usuario pueda ocultarlo. La elección de cualquiera de las dos alternativas depende de la naturaleza y necesidad del texto. En mi caso, es un texto que sólo hay que consultar de forma ocasional, con lo que interesa que la mayor parte del tiempo esté oculto. Por eso al cargar la página el texto no se muestra. Si fuera un mensaje de lectura obligatoria, para que nadie pueda decir que no lo ha visto, por ejemplo, pues comenzaría con el texto visible y el botón permitiría ocultarlo (y visualizarlo de nuevo, claro). En fin, estos detalles parecen tonterías pero muchas veces son tonterías importantes, así que si uno se encuentra situaciones similares, es buena idea dedicarle una pensada de unos minutos o, mejor aún, preguntarle a los usuarios, que son quienes al fin y al cabo van a valorar la utilidad del software.

Pasando ya a lo meramente técnico, nos basaremos en tres cosas:
  • identificadores de elementos
  • código HTML de un elemento (propiedad innerHTML)
  • botón con una función Javascript asociada

Identificadores de elementos

Prácticamente cualquier elemento de una página puede tener un identificador (un id) que podemos utilizar para hacer referencia a él desde código Javascript. Esto incluye también a los párrafos, así que en vez de escribir

<p>Párrafo de texto</p>

Escribiremos

<p id="mensaje">Párrafo de texto</p>

Para poder manipularlo desde el código Javascript, accederíamos a ese elemento con la llamada

document.getElementById("mensaje");

Queremos comenzar con el texto oculto, lo que equivale a decir que el texto inicial del párrafo esté vacío. Debajo de ese párrafo pondremos un botón y debajo del botón, el resto de la página:


1 <p id="mensaje"></p>  
2 <button id="bInfo1" onclick="botonPulsado()">Mostrar mensaje</button> 
3 <p>Aquí va el resto de la página</p>

Como puede verse, el botón responderá al clic invocando a la función botonPulsado, que mostraremos más adelante.

Código HTML

Por otro lado, algunos elementos DOM tienen la propiedad innerHTML, que es un valor textual que representa el código HTML asociado a ese elemento. En el caso de un párrafo, es el texto HTML que se mostrará dentro. Esta propiedad puede ser tanto de lectura como de escritura, así que podemos recuperar el valor del párrafo o podemos asignarlo. Por ejemplo:

texto = "hola, caracola";
document.getElementById("mensaje").innerHTML = texto;

La función Javascript

Por último, necesitaremos una función que cambie el contenido del párrafo en cada pulsación del botón, mostrando u ocultando el texto, alternativamente. Esto se hará comprobando si el párrafo en ese momento está vacío o no:

    if (document.getElementById("mensaje").innerHTML == "") {
        document.getElementById("mensaje").innerHTML = texto;
        document.getElementById("bInfo1").innerHTML = "Ocultar mensaje";
    } else {
        document.getElementById("mensaje").innerHTML = "";
        document.getElementById("bInfo1").innerHTML = "Mostrar mensaje";
    }

Con esto, ya tenemos las tres piezas de nuestro pequeño puzzle. Así quedaría la página completa:



01 <HTML>  
02 <HEAD> 
03 <script> 
04 function botonPulsado() { 
05 texto = 'Esto es un bloque de texto <br>\  
06 que debería poder mostrarse u ocultarse <br>\  
07 según lo desee el usuario. Por ejemplo, unas<br>\  
08 instrucciones de cómo actuar en determinados casos,<br>\  
09 o unos teléfonos de contacto de emergencia...<br>\  
10 En general, cualquier información útil que tenga que<br>\  
11 estar rápidamente accesible<br>'  
12 if (document.getElementById("mensaje").innerHTML == "") { 
13 document.getElementById("mensaje").innerHTML = texto;  
14 document.getElementById("bInfo1").innerHTML = "Ocultar mensaje";  15 } else { 
16 document.getElementById("mensaje").innerHTML = ""; 
17 document.getElementById("bInfo1").innerHTML = "Mostrar mensaje"; 18 }  
19 }  
20 </script> 
21  
22 </HEAD> 
23 <BODY> 
24 
25 <H1>Página importantísima, con un mensaje secreto</H1>  
26  
27 <P ID="mensaje"></P>  
28 <BUTTON ID="bInfo1" ONCLICK="botonPulsado()">Mostrar mensaje</BUTTON>  
29 <P>Aquí va el resto de la página</P>  
30  
31 </BODY>  
32 </HTML>

Listado 1. La página al completo

Y si la probamos veremos el resultado de las imágenes:


Y una vez pulsado el botón


Unos comentarios finales

Como vemos, la técnica de mostrar y ocultar un elemento es muy sencilla, pero también muy versátil. Se puede utilizar, entre otras cosas, para
  • textos de instrucciones, notas legales o mensajes de ayuda para el usuario
  • bloques de iconos
  • una sección de enlaces corporativos
  • ...y cualquier otra cosa que se os ocurra y para la que tenga sentido verse y ocultarse
Como curiosidad, os comento que un par de usuarios me han felicitado efusivamente por el resultado. Para ellos, resulta muy práctico olvidarse de mirar los papeles cuando están en la página y tienen que consultar la normativa. La técnica empleada en la página, desde un punto de vista técnico, es una trivialidad, pero oyendo sus alabanzas parece que uno les hubiera hecho la aplicación del siglo, ya que han quedado muy satisfechos.

Esto viene a recordarnos que no todo es calidad técnica o calidad objetiva, sino que también es muy importante la calidad percibida por el usuario. De hecho, podemos rompernos la cabeza ideando virguerías técnicas y haciendo que nuestro programa sea una maravilla tecnológica, pero si los usuarios no lo perciben así, entonces quizás no tiene tanta calidad. O sin quizás.

Quien de verdad puede valorar algo es quien lo usa. Esto no es una verdad absoluta (recordemos el caso de los coches de Volkswagen: los usuarios podían estar satisfechos con la conducción, comodidad... pero su calidad tecnológica no llegaba a las exigencias legales en materia de emisiones), pero es importante tener en cuenta qué cosas podemos dar que aporten mayor valor a los usuarios de nuestras aplicaciones.

Esas cosas que aportan valor no siempre han de suponer un esfuerzo técnico muy alto, así que es bueno estar atentos para detectarlas y poder darlas. Así, con poco esfuerzo podemos aumentar el nivel de satisfacción de nuestros usuarios. Que los usuarios estén contentos es bueno para ellos y mejor aún para nosotros.

Bueno, aquí corto ya el rollo. A seguir programando.Y que los usuarios de vuestros programas os lo agradezcan, al menos ahora que se acerca la Navidad.


martes, 3 de noviembre de 2015

Solución quick-and-dirty para contar funciones

Pregunta 1: ¿Cuántas funciones escribiste para tu último proyecto en PHP? No cuentes las de librerías de terceros

grep -r "function " --include="*.php"  .|grep -v "./libs" |wc -l
1291




Pregunta 2: ¿Puedes sacar un listado de ellas, ordenado por los nombres de los ficheros en los que se encuentran?

grep -r "function " --include="*.php"  .|grep -v "./libs" |sort >funciones.txt





 Las dos líneas de código se explican casi por sí solas, en todo caso puede requerir una brevísima consulta a la ayuda de grep (grep --help), así que no me molestaré en explicar lo que ya está escrito allí. Una vez entendidas las opciones, se entiende muy fácilmente.


VAMOS A PONERLE PEGAS

1. En la primera solución se realizan dos llamadas al comando grep, cuando se podría hacer en una. Además, el primer grep obtiene líneas que luego desechará el segundo grep ==> Ineficiente.

2. Además de lo que se pretende, también muestra aquellas líneas que tengan la palabra 'function' seguida de un espacio, aunque estas estén entre comentarios ==> Aunque en mi caso es poco probable que se dé esa situación, sin embargo es algo potencialmente inexacto (si hay algún comentario en inglés conteniendo esa palabra)

Resumiendo: Ineficiente, potencialmente inexacto...

Y seguramente tiene muchas más pegas.



Y SIN EMBARGO... TE QUIERO

Pero tiene una ventaja brutal: es definitivamente rápido de hacer. Muy rápido. Y rápido, también, de ejecutar (en nuestro caso, dado el lote de ficheros con los que tengo que trabajar). Así que, ¿por qué hacerlo más complicado cuando una solución quick-and-dirty puede valer?

Y es que, a veces, lo perfecto es enemigo de lo bueno. O como dijo R. Gabriel, lo peor es lo mejor. Pero de esto ya hablaremos en otra ocasión.

martes, 27 de octubre de 2015

Por dónde se mueve la serpiente

Desde hace poco, estoy flirteando un poco con Python, y entre otras pruebas que estoy haciendo, tengo un programa que quiero que me funcione tanto en Linux como en Windows.

¿Cómo hacer que el programa sepa si está en una u otra plataforma? (Por ejemplo, para tratar con las rutas de ficheros, o para buscar determinados directorios de sistema que tienen nombres predefinidos...)

En realidad, para esas dos cosas que he dicho, debería usar variables del sistema o constantes predefinidas (separador de directorios, directorio del usuario... que tengo pendiente de investigar), pero es posible que aún y así todavía quiera seguir sabiendo cómo conocer en qué sistema operativo se está ejecutando el programa.

Simplemente hay que importar el módulo (librería) platform, e invocar el método system, que devolverá la cadena 'Windows' o 'Linux'.

Pues ya está. Aquí el listado:

 1 import platform
 2 print("Mostrar información sobre el ordenador")
 3 
 4 # Windows o Linux?
 5 if platform.system() == "Windows":
 6    print("En Windows")
 7    raiz = 'c:\\'
 8 elif platform.system() == "Linux":
 9    print("En Linux")
10    raiz = '/'
11    
12 print('------------------------------------------------------------------------')
13 print(platform.uname())
14 print('------------------------------------------------------------------------')
15 print('Arquitectura:')
16 print(platform.architecture())
17 print('Implementación: ' + platform.python_implementation())
18 print('------------------------------------------------------------------------')

Listado 1: Diferenciar entre Windows y Linux con platform.system()

Como podéis ver, hay otros métodos interesantes: uname, architecture y python_implementation, que nos pueden dar información que puede que necesitemos en algún caso. Aunque si queremos maximizar la portabilidad de nuestros programas, deberíamos usar esto lo menos posible, para no atarnos en demasía a una plataforma específica. Que sí, que luego siempre se acaba migrando, aunque uno no quiera. Y las dependencias de la plataforma son un lastre.

La llamada a uname devuelve un array con bastante información (contiene, entre otras, el tipo de sistema, como lo devuelve system).

La salida en Ubuntu la podéis ver aquí:



Y aquí en Windows 7:


Por último, avisar de que este código está hecho para Python 3, así que no olvidéis poner en la primera línea del archivo la ruta del ejecutable de python3. También os dejo aquí cómo indicar que el encoding del archivo es UTF-8, cosa que os será útil si trabajáis con eñes, tildes y otras 'cosas raras'. Simplemente hay que poner en las dos primeras líneas esto:

#!/usr/bin/python3
# -*- encoding: utf-8 -*-



viernes, 9 de octubre de 2015

Enviar mensajes de Telegram desde una aplicación web

Seguro que muchos conocéis Telegram, esa aplicación de mensajería instantánea que intenta hacerle la competencia a WhatsApp, aunque de momento, todo sea dicho, no le llega ni a la suela de los zapatos en cuanto a popularidad, y esto a pesar de tener algunas características bastante superiores. Pero bueno, la historia de la tecnología está llena de ejemplos en los que un producto técnicamente superior se ve desbancado por otro técnicamente inferior, y es que no sólo los detalles técnicos pesan. Sin embargo, leo que Telegram va creciendo gradualmente, así que espero que algún día la mayoría de mis contactos se hayan mudado de WhatsApp a Telegram. Mientras tanto, a seguir con las dos aplicaciones

No quiero entrar en los detalles técnicos ahora, y la evangelización sólo la hago los domingos, así que mejor os remito a esta entrada en hipertextual.com donde explican razonablemente bien las diferencias más importantes entre ambas aplicaciones. Lectura muy recomendable.

http://hipertextual.com/2015/06/telegram-vs-whastapp

¿Ya la habéis leído? Bien. Ahora, vamos al turrón.

1. Los bots de Telegram

El 24 de junio de este año Telegram lanzó una característica que no he podido investigar hasta hace tan solo unos días (muy por encima, eso sí, aunque suficiente para lo que yo quiero hacer): los bots. [https://telegram.org/blog/bot-revolution]

Fig1. Los bots de telegram: una innovación muy interesante

Estos bots son cuentas de Telegram detrás de las cuáles no hay una persona, sino un programa, y sin necesidad de un número de teléfono asociado. Y son ideales para muchas cosas. Entre ellas, para que tus programas te puedan mandar mensajes al móvil, por ejemplo, aunque según parece esta es la menor de las utilidades que tienen. Pero es la que hoy me interesa.

El proceso básicamente consiste en tres pasos: 1) crear el bot, 2) chatear (unirse) a él todos aquellos que quieran recibir los mensajes y 3) enviar y recibir mensajes como si no hubiera un mañana

Ok, pues manos a la obra.

2. Crear un bot


Para esto se utiliza el BotFather, el padrino-de-los-bots (confío en que no habrá que explicar el juego de palabras. Si no, dejad de leer y sacad de la biblioteca la serie de películas de "El Padrino").

Simplemente, hay que entrar en la dirección [https://telegram.me/botfather]
y seguir las instrucciones que nos va dando.

Veremos un mensaje tal que así


Fig. 2. El padrino nos recibe en su casa


Podemos interactuar con el BotFather "chateando" directamente, teniendo en cuenta que las órdenes comienzan con una barra /, o bien podemos usar el botón que os he señalado con una flecha en la figura 2.

Creamos el bot con /newbot y le damos un nombre


Fig. 3. El bot recién creado, de nombre "Cosicas"

A continuación le damos un nombre de usuario, que termine en "bot". Esto nos devolverá un token que necesitaremos pasar en las invocaciones al bot, para poder enviar mensajes. Lo copiamos y lo guardamos en un lugar seguro. Lo necesitaremos un poco más adelante.


Fig. 4. Al darle el nombre de usuario recibimos un token



El bot posee una serie de métodos que podemos invocar a través de la URL

https://api.telegram.org/bot<token>/METHOD_NAME

Donde METHOD_NAME puede ser uno de los métodos que podéis consultar en la referencia de la API (aquí [https://core.telegram.org/bots/api]).

Por ejemplo, invocando al método getMe podemos obtener información básica del bot, entre ella el ID que lo identifica:

https://api.telegram.org/bot<token>/getMe

En mi caso, esto:


Fig. 5. Uso del método getMe para extraer el ID de nuestro bot


3. Chatear con el bot


A continuación debemos unirnos a la "conversación" con nuestro bot. Para esto, pinchamos en el enlace que nos ha dicho el BotFather en la figura 4. Es un enlace del tipo telegram.me/CosicasBot (que a su vez redirige a https://web.telegram.org/#/im?p=@CosicasBot). Allí veremos un botón que nos servirá para iniciar nuestra conversación con el bot.


Fig. 6. Accediendo a la "conversación" con el bot

Pulsamos en INICIAR y



Fig. 7. Ya estamos conectados a nuestro bot. Listos para enviar mensajes.


Al iniciar el chat con el bot, ya podemos obtener nuestro identificador para que nuestro programa pueda enviarnos mensajes. El chat_id identifica a nuestro usuario en Telegram, y el bot necesita saber este chat_id para poder enviarnos mensajes. En una reciente actualización he leído que también se puede hacer con el nombre del usuario. Yo voy a explicarlo con el chat_id.

¿Y cómo obtenemos ese chat_id? Un pequeño truco que he visto es invocar al método getUpdates de nuestro bot, tal y como describimos en el apartado anterior. Eso debería producir una respuesta en formato JSON que, entre otras cosas, lleva nuestro chat_id. Es decir, abrimos un navegador y tecleamos la URL siguiente:

https://api.telegram.org/bot<token>/getUpdates

Y deberíamos ver algo así:

 
Fig. 8. Forma "chapucerilla" de obtener el chat_id


En el recuadro rojo tenéis el chat_id.

4. Enviar un mensaje

Bueno, pues parece que ya lo tenemos todo. Ahora ya podemos crear una página PHP sencilla que envíe mensajes al bot. Sería algo tan simple como:



Fig. 9. Código para enviar un mensaje al bot

Por supuesto, no es necesario que sea PHP, puede estar escrita en cualquier lenguaje. Lo necesario es simplemente invocar la URL que se construye en la línea 15.

Por último, abro ese fichero PHP en mi servidor web y me voy al Telegram en mi móvil, et voilà!


Fig. 10. Mi PHP enviándome mensajes al móvil, ¡qué tierno!


Bueno, pues ahí tenéis una forma rápida de enviar mensajes al móvil vía Telegram desde vuestros programas. Pero ojo a los bots, que parece que tienen un gran potencial mucho más allá de esto.

Por cierto, el bot que he usado de ejemplo voy a cargármelo ahora mismo, que no quiero que nadie empiece a mandarme basura. Quien quiera probarlo, que se cree el suyo propio.



Fig. 11. Borrando el bot de este ejemplo

Bueno, seguramente habré cometido varios errores en este artículo, pero acabo de empezar a pelearme con los bots (tampoco creo que les dedique mucho más, ya tengo lo que quería) y seguro que algunas cosas las iré aprendiendo mejor en los próximos días.

Y por hoy, basta de programación.

lunes, 17 de agosto de 2015

Localizar ficheros en Linux

Un programa que me parece una maravilla en Windows es Everything, y no he encontrado nada en Linux que se le parezca. No concibo una sesión de trabajo en mi ordenador Windows sin este programa. Ojalá aparezca algo similar para Linux.

Pero no todo está perdido en Linux. Aquí tenemos el programa locate, con el que podemos hacer cosas "parecidas" (aunque ya quisiera yo que tuviera la potencia y el bajo impacto en memoria y procesador que tiene Everything).

Un ejemplo: para localizar todos los ficheros de configuración de MySQL que hay en mi equipo, escribiría algo así:

$ locate my.cnf

Y la salida es algo como esto:

Fig. 1. Localizando todos los ficheros "my.cnf" en mi equipo

Si además quiero abrirlos todos ellos en un único paso, podemos hacer

$ locate my.cnf | xargs gedit

Y se nos abriría una ventana como esta

Fig. 2. Todos los ficheros my.cnf abiertos en gedit

Ojo: esto funciona porque gedit acepta múltiples parámetros en la línea de invocación. Si el visor que vamos a utilizar no soporta múltiples parámetros, habría que hacerlo de otra manera.

El nombre que se le pasa como argumento a locate es un patrón, no tiene por qué ser el nombre literal. Esto quiere decir que buscará ficheros que contengan el patrón especificado en su nombre. Por ejemplo, podríamos haber listado los ficheros anteriores tecleando un carácter menos:

$ locate my.cn

Y el resultado sería el mismo, ya que los ficheros implicados CONTIENEN el patrón especificado

Fig. 3. Todos los ficheros my.cn* del equipo

Fijaos que el patrón no es exactamente una expresión regular, ya que no hace falta poner el * para indicar que puede haber más caracteres después de la "n" y, sin embargo, así es cómo locate hace la búsqueda.

Si elimino la letra "n" del patrón, podemos ver que aparecen más ficheros

Fig. 4. Aparecen otros ficheros que coinciden con el patrón *my.c*

O sea, que es como si el patrón tuviera al principio y al final un * (o, para los que estáis más habituados al mundo SQL, como si se hiciera una búsqueda LIKE '%PATRON%')

Así, por ejemplo, si quiero buscar todos los ficheros JPG que tengo en el equipo, no hay que buscar con el patrón *.jpg, sino simplemente teclear

$ locate .jpg

Fig. 5. Listado de ficheros .jpg existentes en mi equipo

Y si lo que quiero es contar cuántos ficheros JPG tengo en el equipo, puedo añadir esto:

$ locate .jpg | wc -l

Fig. 6. ¿Más de 2.000 imágenes????



Si queremos, podemos utilizar expresiones regulares en el patrón utilizando la opción --regex. Así, para buscar todas las imágenes JPG que empiezan por "yellow" pondríamos algo como

$ locate --regex yellow.*.jpg

Y el resultado, en mi equipo, son dos ficheros

Fig. 7. Las imágenes JPG que comienzan por "yellow*"

Que podríamos haber abierto así:

$ locate --regex yellow.*.jpg | xargs eog

Ojo: he utilizado como visor de las imágenes eog (Eye of Gnome) ya que éste soporta múltiples ficheros en una invocación. Sin embargo, shotwell, el visor por defecto de Ubuntu, no los soporta y daría un mensaje diciendo que hay parámetros de más en la invocación.

Al contrario que Everything, que monitoriza el sistema de ficheros constantemente (algo posible gracias al journal de NTFS), la base de datos de locate no se actualiza con tanta frecuencia. Ahora no tengo tiempo de investigarlo, pero me da a mí que se actualiza en cada reinicio del sistema. Lo que sí se puede hacer es actualizarla a mano con el comando updatedb:

Fig. 8. Actualizar a mano la BD de locate

(Lo de "sudo" he tenido que ponerlo porque si no me daba problema al crear algún fichero temporal).



Bueno, pues dicho todo lo anterior, ya podéis buscar rápidamente todos esos ficheros que os gustaría renombrar, por si las moscas...

Fig. 9. Ficheros que hay que renombrar urgentemente

miércoles, 12 de agosto de 2015

Notificaciones en Ubuntu

El escenario

Llego al curro y me dicen que durante mi ausencia me ha llamado Claudia Schiffer para ver si le puedo hacer una sesión de fotos y darle cremita, que le apetecía a la zagala irse a la playa. Como no me ha localizado, ha pedido que por favor le devuelva la llamada, pero a una hora concreta, ya que cuando me llamó Claudia se iba a cortarse las uñas y no podría contestarme durante un rato. La hora a la que me ha dicho que la llame es dentro de 20 minutos.

Yo llego, me siento delante de mi ordenador a buscar en Google fotos de Claudia trabajar y espero ansiosamente tranquilamente a que pasen los 20 minutos para llamarla. Probablemente no se me olvide (la Schiffer no me llama todos los días), pero puede que quiera asegurarme de no olvidarlo. Puedo ponerme una alarma en el móvil, pero, ya que voy a estar trabajando con el ordenador ¿no sería mejor que me saltara un aviso en pantalla dentro de 20 minutos?

Hay varios programas en una distribución estándar Ubuntu que podemos utilizar para mostrar un mensaje. Combinando estos con sleep (esperar X segundos, en este caso los 20 minutos equivalen a 1200 segundos), puedo hacer esto que acabo de explicar. Los comandos que siguen están probados en una instalación estándar de Ubuntu 15.04. En todos los casos, abriré una consola, me mandaré el aviso y a continuación me pondré a "trabajar" en una hoja de cálculo, a esperar a ver qué pasa con la notificación.

1. notify-send


$ sleep 1200; notify-send "Llama a Claudia que te está esperando"

Esto mostrará uno de esos mensajes "globo" que aparecen en la esquina superior derecha de la pantalla y desaparecen al cabo de unos pocos segundos (Fig. 1).


Fig 1. Un globo avisándome de que tengo que llamar a mi musa

Como se puede ver en la captura de pantalla, para la prueba de concepto he cambiado el número de segundos a 4, pero esto no afecta para nada a la discusión.

El problema puede ser que la notificación de globo, al no quitarle el foco a la ventana en la que estemos actualmente, sigamos concentrados en la pantalla y no lo veamos (aunque reconozco que es un poco difícil no verlo, la verdad).

2. xmessage

$ sleep 1200; xmessage "Llama a Claudia que te está esperando"

Esto hará que salte un diálogo con un botón aceptar ("okay" en mi distro). Esta sí que roba el foco, así que no podemos ignorarla sin más. Eso sí, es posible que si con el ratón hacemos clic en otra ventana, la notificación quede tapada. Un problema que puede que hayáis apreciado es que la tilde del mensaje no sale correctamente. Normalmente, el mensaje saldrá en una esquina inferior (en diversas pruebas me ha salido tanto en la esquina inferior derecha como en la izquierda, sin que yo sepa muy bien por qué). Podemos usar la opción -center para que salga en el centro de la pantalla (Fig. 2).

Fig 2. Mensaje en el centro de la pantalla.¡Mis tildes!

3. zenity


El comando zenity permite lanzar diversos tipos de cuadros de diálogo desde nuestros scripts o desde una consola. El programa 'gdialog' es un envoltorio sobre 'zenity', así que mejor usar zenity directamente.

Estos diálogos pueden ir desde mostrar un simple mensaje al usuario (opción --info) hasta pedirle que introduzca algunos datos (un texto, una fecha [opción --calendar], elegir una opción de una lista...). Los valores devueltos por zenity se pueden capturar en el script invocante y asignarlos a una variable, por ejemplo, para trabajar con ellos (muy interesante).

Para mostrar un simple mensaje sin interés en capturar la salida, podríamos escribir algo así como:

$ sleep 4; zenity --info --text="Llama a Claudia que te está esperando"

Y veríamos algo similar a lo que se ve en la Fig. 3.

Fig. 3. Un diálogo de mensaje con zenity. Es tímido, se queda detrás

El problema es que zenity NO adquiere el foco, así que queda detrás de la ventana activa. Si ésta ocupa toda la pantalla... malo. También podéis ver en la fig. 3 que aparece un warning en consola. Esto no es un problema, pero no me gusta.

4. Conclusión


Tras unas cuantas pruebas, mi preferida para este tipo de recordatorios es notify-send combinada con sleep, pues me gustan esos globos que no interrumpen el trabajo y que son suficientemente visibles. Además, no hay que pasar ningún parámetro para que funcione bien, con lo cual es rápido de teclear y no hay que andar recordando opciones (o mirando la ayuda) como en zenity, por ejemplo.

Si tuviera que capturar información del usuario (un texto, el botón pulsado...) utilizaría seguramente zenity.

En cualquier caso, echadle un vistazo a la ayuda de las tres herramientas, que son altamente configurables. También existen muchas otras herramientas para hacer cosas parecidas, así que si éstas que os he presentado aquí no os resuelven del todo vuestros problemas, investigad un poco.

Bueno, os dejo, que ha llegado la hora de llamar a Claudia...¡ains, qué nervios!

viernes, 17 de julio de 2015

Cambiar el nombre del equipo en Ubuntu



El equipo en el que estamos trabajando tiene un nombre, que se puede consultar con el comando 'hostname' tanto en Linux como en Windows.


¿Y para cambiarlo?

En la última instalación de mi Ubuntu no estuve muy acertado al elegir el nombre de equipo, y ahora me gustaría cambiarlo.

Simplemente, hay que editar estos dos ficheros:

/etc/hostname
/etc/hosts

Y ya está.

Bueno, en mi caso, además tuve que reiniciar.

En Windows se puede cambiar desde la interfaz gráfica, en Propiedades de "Equipo" o "Mi PC" (según versión).

Gracias a la comunidad Ubuntu por esta información, que podéis consultar, junto con muchas otras cosas útiles, aquí. Aunque hay que reconocer que la web está un poco dejada...

viernes, 10 de julio de 2015

Aversión a las versiones

Escudos y bichos con alas encima: mismo tema, diferentes versiones
(Baeza, palacio de Jabalquinto)

Aunque resulte difícil de creer, hay usuarios que no saben con qué versión de Windows están trabajando.

- José, tengo no-recuerdo-qué-problema con el ordenador de mi casa. ¿Cómo lo arreglo?
- Hmm... ¿qué versión de Windows tienes? (ya paso de preguntar qué versión de "sistema operativo", porque entonces me toca explicar qué es eso)
- Pues... no sé... ¿el 2007?
- No, eso es el Office que tienes pirateado

Como diría Forges: Gensanta.

Parece una trivialidad saber la información del sistema operativo, o que puede que esto no tenga demasiado interés, pero el asunto puede traer más cola de lo que parece. Así que allá van algunas formas de saber la versión del Sistema Operativo con la que estás trabajando.

1. Windows, modo gráfico

Ir a Inicio / Panel de Control / Sistema
Dependiendo de la versión, verás una ventana u otra, pero en cualquier caso, por algún lado te debería informar acerca de  la versión.

En Windows XP y Windows 7 se ve algo así:

Fig. 1. Información de la versión y algo más en Windows XP



Fig. 2. Información de la versión y algo más en Windows7

En ambos casos, además de la versión del SO, también se da información sobre el equipo como memoria, parches instalados, velocidad del procesador... En fin, que merece la pena echarle un vistazo.


2. Windows, modo ventana negra
La opción gráfica está bien para los usuarios "normales" pero, como informáticos, a veces puede que queramos utilizar la información de la versión en un programa, por ejemplo, un script que recupere esta información del SO y tome las decisiones oportunas.

En principio, podemos abrir una ventana de comando (Inicio / Ejecutar... cmd) y... y nada más. En Windows XP y Windows 7 la propia ventana ya te muestra una línea con la versión, aunque puede ser un poco críptico entender que la versión 6.1.7601 es en realidad Windows 7

Fig. 3. Tengo el Windows 6.1.7601. ¡Qué sorpresa!

No obstante, si queremos usar la información en un script, necesitaremos un comando que devuelva esa información. Como podéis ver en la Fig. 3, el comando ver permite obtener esta información.

Al menos Windows XP sí que te pone, antes del numerito, que estás utilizando Windows XP

Fig. 4. Y este es el XP



 3. Linux, modo gráfico
Cada distro de Linux es un mundo, así que yo sólo puedo hablar de Ubuntu 15.04, que es lo que tengo actualmente. En ese caso, en la pantalla de login inicial se muestra la información:

Fig. 5. Información sobre la versión en Ubuntu 15.04, antes de entrar


4. Linux, modo ventana
Pero de nuevo, si nos interesa obtener la información en un comando para usar esto en nuestros scripts, podemos utilizar el comando lsb_release con el parámetro -a (lo de LSB significa Linux Standard Base, por si ardíais en deseos de saberlo, que os conozco)

Fig. 6. Comando lsb... (LSB = ¿Lo SaBe? ¡Vivan los chistes malos!)

Desconozco si este comando es el mismo en otras distros, aunque imagino (más bien, espero) que sí.

En cuanto al comando, me gusta más cómo lo hace Windows. Creo que "ver" es bastante intuitivo y fácil de recordar para recuperar la VERsión, mientras que el comando de Ubuntu no me parece tan recordable (entre otras, esa es una de las razones por las que escribo estas notas para mí). Sin embargo, en la información que devuelven, veo mucho más legible la de Ubuntu que la de Windows 7.


5. Android y similares
Ya puestos, pongamos también cómo consultarlo en Android, porque muchas veces las aplicaciones que podemos instalar están limitadas por la versión de Android, y aquellos usuarios para los cuáles yo soy su servicio-técnico-del-móvil con frecuencia no saben la versión de Android que lleva su móvil. Imagino que esto os pasará a más de uno.

Lo de "similares" que he puesto en el título de este apartado es que en mi caso, en vez de mirarlo en un Android "estándar" de Google, yo tengo el CyanogenMod, pero vamos, para el caso, es lo mismo.

Para ver la versión en estos SO, hay que entrar en Ajustes / Información del teléfono y buscar una entrada similar a esta

Fig. 7. Version de Android / Cyanogenmod


6. La anécdota
Y por último, y hablando de versiones de sistemas operativos, dejemos hueco para la anécdota. Como sabréis, tras el récord de permanencia de XP (mira que ha durado años en nuestros equipos: era una buena herramienta), las versiones de Windows se han sucedido en los últimos años a una velocidad algo rápida: Windows 7, Windows 8 y... ¿Windows 9? Pues no, directamente ahora llega Windows 10. Y, aunque no hay una explicación oficial para este salto, esta entrada de Genbetadev comenta algunas de las bromas que se han utilizado para explicar este hecho. Y después acaba mostrando código REAL que parece hecho de broma. Muy ameno, bien explicado y recomendable para quién tenga que programar y pelearse con la versión del sistema operativo.

jueves, 9 de julio de 2015

Generar RTF desde nuestras aplicaciones

A veces puede ser muy interesante que nuestra aplicación genere un fichero RTF que luego los usuarios puedan editar con Word o Writer para modificar, imprimir, convertir a diferentes formatos como PDF, docx, odt...

La buena noticia es que los RTF son simplemente ficheros de texto con unas etiquetas especiales que indican el formato del texto, de las tablas, de las imágenes y de los demás elementos. Así que no es difícil hacer un programa que vaya escribiendo este tipo de etiquetas combinadas con el texto a incluir.

La mala noticia es que los distintos editores con capacidad para crear un RTF tienen distintas opiniones acerca de lo que debe incluirse en un documento con Formato de Texto Enriquecido (que es lo que significa más o menos la sigla RTF, Rich Text Format).

Si creáis un RTF sencillo con cualquier editor ofimático, tendréis algo así (en este caso, parto de un RTF creado con LibreOffice Writer 4.4 en Ubuntu):


Fig. 1. Un RTF sencillo

Y ahora, si en vez de hacer doble clic sobre el icono del fichero, lo abrís con un editor de texto podréis ver algo similar a esto:

Fig. 2. Las tripas del RTF (versión LibreOffice Writer)

Si abrimos ese mismo RTF con Word 2003 y lo volvemos a guardar, vemos que Word le ha metido bastante más información

Fig. 3. El RTF después de pasar por las manos de MS-Word, el cual ha decidido añadirle muuuuuuchas cosas

Por último, lo he abierto y vuelto a guardar con WordPad (de Windows 7) y veo que es el que deja el RTF más limpito, con aparentemente la menor cantidad de información.

Fig. 4. El RTF exportado con WordPad (Windows 7)

Como es lógico, los tres ficheros difieren bastante en el tamaño, ya que la versión de Word es la que más información lleva (8 KB) y la versión de WordPad es la más pequeña (225 bytes).

Como curiosidad, decir que he generado un RTF a mano con el editor de texto y dejándolo en algo tan reducido como esto


Fig. 5. Un RTF superreducido generado a mano

Aquí podéis ver los tamaños de las distintas versiones


Fig. 6. A menos paja, menos tamaño

Ojo, el caso manual tiene "trampa", pues me he saltado algunas partes que son necesarias según la especificación oficial del formato RTF, pero como los programas prefieren rellenar la falta de información con valores predefinidos antes que morir dando un error miserablemente, podemos abrir este documento hecho a mano sin problemas en Word 2003, WordPad y LibreOffice 4.3 (tanto versiones de Windows como de Ubuntu), que ya se encargan ellos de asignar valores por defecto a todo lo que no se especifique (fuentes de texto, colores...). Eso sí, cada uno de estos programas le ha puesto un tipo de letra y un tamaño a su antojo, ya que el documento creado de forma manual no indica nada respecto a las fuentes a utilizar, así que los valores por defecto juegan aquí un papel fundamental.

En próximas entradas entraré en los detalles de los RTFs, a fin de que nuestras aplicaciones puedan generar este tipo de ficheros sin demasiadas complicaciones.

Por de pronto, los impacientes pueden ir empezando a leerse la especificación oficial:

http://www.biblioscape.com/rtf15_spec.htm

Para mí ha sido la Biblia durante unos cuantos días.
Related Posts Plugin for WordPress, Blogger...