Hace muchos años, la programación multihilo solo servía para darnos a los usuarios la sensación de multitarea y que el ordenador pudiera respondeer cuando interactuábamos con él. Normalmente sólo teníamos un único núcleo de CPU y solo podía ejecutar una cosa en un momento del tiempo determinado. Aunque el sistema operativo se encargaba de ir cambiando las tareas que iba ejecutando varias veces por segundo, y por eso podíamos estar viendo una página web y al mismo tiempo chateando con otro programa, copiando un archivo, etc. Esta multitarea también nos ayudaba mucho cuando una aplicación estaba esperando un dato del disco o de un dispositivo (ratón, teclado, red...), ya que estos dispositivos son mucho más lentos que la CPU del ordenador. Es decir, mientras la CPU puede procesar millones de operaciones por segundo, pedir un dato a un disco duro, puede tardar lo mismo que tardarían varios miles de operaciones, y si el dato viene de Internet, puede tardar mucho más. Así que los sistemas operativos multitarea, suspenden la ejecución de dicha aplicación hasta que el dato esté listo, y así aprovechan los ciclos de procesador que podían haberse perdido para hacer cosas más productivas como la descompresión de fotogramas de un vídeo de gatitos.
Eso sí, si en una CPU monohilo ejecutamos dos tareas que requieren CPU de forma intensiva como la compresión de vídeo, renderizado 3D o aplicación de filtros sobre imágenes, nos daremos cuenta de que el tiempo total de la ejecución de las tres tareas es aproximadamente el mismo que ejecutar una tarea detrás de otra.
Pero en los tiempos que corren, es muy común encontrar procesadores con varios núcleos, incluso con varios hilos por núcleo. Al tener varios núcleos, podremos ejecutar varios programas y normalmente el sistema operativo se encarga de colocarlos en uno u otro núcleo, de forma que, ya que nuestro procesador puede ejecutar varias cosas a la vez, aprovechemos esa potencia para terminar las tareas antes.
Aunque ahora el problema suele ser que las aplicaciones no están pensadas para ejecutarse en varios hilos. Bueno, actualmente muchas aplicaciones pueden aprovechar la potencia de los procesadores modernos, como compresores de vídeo, software de minería de criptomonedas, tratamiento de imágenes etc. Pero, muchos programas comunes de búsqueda de datos en ficheros, compresión/descompresión, y muchos de nuestros scripts en Bash o Python no están preparados.
Cuando, en Bash queremos ejecutar dos tareas a la vez, siempre podemos ejecutarlo con un & al final, volveremos a nuestro shell para ejecutar más cosas mientras el programa inicial se está ejecutando:
$ programa & 19238 $ … ejecuto más cosas …
O también podemos ejecutarlo normalmente, pulsar Control+Z (^Z). El programa se detendrá, si escribimos en la consola "fg" el programa seguirá en primer plano (foreground), pero si ponemos "bg" el programa seguirá en segundo plano (background), y mientras éste está corriendo, podremos ejecutar más cosas:
$ programa … ^Z [1]+ Stopped programa … ejecuto más cosas … $ fg programa … programa sigue ejecutándose … ^Z [1]+ Stopped programa $ bg [1]+ programa & … puedo ejecutar lo que quiera …
Con esto puede ser suficiente para muchos de nosotros pero, ¿y si queremos utilizar más hilos? Es un poco pesado ejecutar varios programas con sus argumentos y una & al final. ¿O queremos que los argumentos vayan cambiando según la ejecución? ¿O incluso queremos ejecutar cientos de tareas pero que se vayan repartiendo la CPU de 2 en 2, de 4 en 4 o más dependiendo del número de núcleos que tengamos? Para eso, y mucho más, tenemos la utilidad GNU Parallel.
Un ejemplo típico es crear un programa que calcule dígitos del número PI con un hilo de CPU, es muy fácil con bc:
#!/bin/bash echo "scale=4000; a(1)*4" | bc -l
Lo salvamos como pi.sh y le damos permiso de ejecución con:
$ chmod +x pi.sh
Este programa, ejecutado en mi ordenador tarda unos 11 segundos en terminar. Suponiendo que nuestro equipo tenga 2 núcleos, podemos hacer:
$ time ./pi.sh & time ./pi.sh
Veremos que tarda también 11 segundos (más o menos). Esto lo podemos hacer con GNU Parallel de esta forma:
$ time seq 2 | parallel -n0 ./pi.sh
Donde se ejecutará el comando pi.sh dos veces y de forma simultánea. Pero, aunque esta orden pueda parecer complicada, podemos jugar un poco con ella, para ejecutar pi 4 veces de forma simultánea:
$ time seq 4 | parallel -n0 ./pi.sh
Si nuestra CPU tiene 4 núcleos, seguirá tardando 11 segundos, en realizar cuatro tareas, pero si nuestra CPU tiene 2 núcleos, tardará más de 22 segundos. Ya que las tareas utilizan mucho la CPU y es un trabajo extra para el sistema operativo intercalarlas para que se ejecuten a la vez. Pero, imaginémonos que queremos ejecutar 4 veces pi, pero que se repartan de 2 en 2, para ello podemos hacer:
$ time seq 4 | parallel -n0 -j2 ./pi.sh
Si queremos, podemos ejecutar un gestor de tareas o el comando "top" con el que veremos qué tareas están en ejecución cada vez.
Ahora vamos a modificar pi.sh así:
#!/bin/bash DECIMALES=$1 echo "scale=$1; a(1)*4" | bc -l
De modo que tengamos que introducir el número de dígitos que queremos de Pi. Así ejecutaremos pi.sh de forma concurrente pero con parámetros diferentes en cada ejecución. Podemos jacer lo siguiente:
$ time echo "1000 2000 3000 4000" | tr ' ' '\n' | parallel ./pi.sh
O si queremos que solo haya dos ejecuciones de pi.sh simultáneas:
$ time echo "1000 2000 3000 4000" | tr ' ' '\n' | parallel -j2 ./pi.sh
Nota: El uso de tr es porque parallel necesita que los argumentos vayan uno por línea. Si los argumentos los tenemos en un archivo y uno por línea podríamos hacer:
$ cat argumentos | parallel -j2 ./pi.sh
Con GNU Parallel podemos incluso combinar argumentos. En este ejemplo, cambiamos de base varios números binarios a base 10
$ parallel echo -n {1}{2}{3}{4} = \;'echo "ibase=2;{1}{2}{3}{4}" | bc' ::: 0 1 ::: 0 1 ::: 0 1 ::: 0 1 0000 =0 0001 =1 0010 =2 0011 =3 0100 =4 0101 =5 0110 =6 0111 =7 1000 =8 1001 =9 1010 =10 1011 =11 1100 =12 1101 =13 1110 =14 1111 =15
Y como vemos, GNU Parallel, además de proporcionarnos una forma sencilla de ejecutar programas simultáneamente, nos proporciona también una forma de combinar argumentos y generar resultados muy potente. Utilizando {1}, {2},...{n} dependiendo del número de argumento que estemos tratando
Uno de mis usos preferidos, es la conversión automática de archivos, o tratamiento de imágenes con ImageMagick. Además, podemos automatizar esta conversión para realizarla en cientos de archivos y despreocuparnos del ordenador ya que él se encarga de hacer el trabajo. Una tarea muy sencilla es convertir un archivo de JPG a PNG con convert. Pero, ¿si tenemos una carpeta llena de archivos? Podemos ejecutar convert en todos ellos, y hacerlo uno detrás de otro, pero podríamos hacerlo, por ejemplo de 2 en 2 o de 4 en 4 dependiendo dee nuestra CPU, incluso podríamos subir a 3 o 5 porque la conversión de archivos implica lecturas y escrituras y es tiempo que podemos estar procesando datos (los archivos convertidos entrarán en el directorio convertidas):
$ find -maxdepth 1 -name ‘*.jpg’ | parallel --progress -j3 convert -verbose {} convertidas/{/.}.png
Fijaos cómo en el segundo argumento le quito la extensión para llamarla png. Podría variar el número del argumento -j según mis preferencias. Además, he introducido --progress que nos indicará el progreso de la tarea.
Como último ejemplo, nos basaremos en el anterior. Pero esta vez, utilizaremos zenity para presentar una barra de progreso de manera gráfica. ¡Porque, que sea terminal no significa que no sea visual!
$ find -maxdepth 1 -name ‘*.jpg’ | parallel --bar convert {} convertidas/{/.}.png 2> >(zenity --progress --auto-kill)
¡Espero que les haya resultado útil!
Normalmente tenemos en ejecución decenas de servicios, y todos deben estar en ejecución en todo momento. Puede que si somos usuarios de escritorio y tenemos un problema, lo detectemos al momento y reiniciemos el ordenador, o incluso investiguemos qué se ha detenido, lo reiniciamos y continuamos trabajando.
Aunque, si tenemos un VPS, una Raspberry PI o un NAS con un pequeño servidor, o cualquier sistema que tenga que estar todo el día encendido de forma independiente ejecutando un sistema GNU/Linux tenemos que tener en mente que los servicios fallan en algún momento. Ya sea por ejecutar una versión experimental, descubrir un bug, o simplemente quedarte sin memoria o disco. La clave es tener previsto que esos servicios pueden sufrir un problema. En el caso de tener un VPS con una web o un blog, significaría dejar a los usuarios sin poder acceder si por ejemplo se cae el servidor web o el servidor de aplicación. O en el caso de una Raspberry implicaría conectarnos o conectar monitor y teclado para reiniciar el servicio a mano, cuando debería ser algo que funcione de manera independiente.
Y como actualmente muchas distribuciones incluyen Systemd, vamos a hacerlo utilizando este sistema.
NOTA: En este tutorial, estoy utilizando sudo para ejecutar acciones con privilegios de root, pero puede que tu sistema no tenga sudo configurado. Así que tendrás que alcanzar el usuario root para ejecutar los comandos.
Para ello, tenemos que tener claro cómo se llama el servicio. En Systemd todos acaban con ".service", algunos ejemplos de servicios pueden ser: apache, nginx (servidores web), sshd (servidor ssh), ufw (firewall), etc.
Podemos obtener un listado de los servicios de nuestro sistema así
sudo systemctl list-units --type=service
Vamos a probar, por ejemplo con el servicio apache2.service, es un servidor web y será muy fácil hacer pruebas con él.
Es posible que este servicio falle. Y es algo que pasa en servidores del mundo real. Puede ser por algún fallo que se haya descubierto y haya sido explotado por un atacante, falta de recursos en el servidor, o incluso un fallo en un módulo, pero no podemos renunciar a ofrecer el servicio a nuestros usuarios. Así que, vamos a matar el proceso, para que éste finalice repentinamente sin contar con systemd:
sudo killall -9 apache2
Lo ejecutamos varias veces, hasta que nos aseguremos de que el proceso está realmente muerto. Si queremos, podemos intentar acceder al servidor web, y asegurarnos de que no responde.
Ahora, vamos a editar el archivo de descripción del servicio. Lo bueno de systemd es que no tenemos que editar el archivo original que describe el servicio, en mi caso /lib/systemd/system/apache2.service. Editar el archivo original implica que si actualizamos el sistema, una actualización puede deshacer nuestros cambios y nos obligaría a revisarlos cada vez que actualicemos. En su lugar podemos editar el archivo /etc/systemd/system/apache2.service o, en versiones más modernas de systemd, podemos ejecutar:
sudo systemctl edit apache2.service
Esto directamente nos mostrará un editor de texto (vi, nano, etc) con un fichero en blanco desde el que podemos introducir modificaciones al fichero original. Los cambios introducidos aquí se sumarán al fichero original y systemd lo interpretará como un archivo que contiene todas las directivas conjuntas. El comando, crea un directorio llamado /etc/systemd/system/apache2.service.d/ y dentro de ese directorio creará el archivo override.conf.
En dicho editor introduciremos lo siguiente:
[Service] Restart=always
Con esto indicaremos a systemd que debe reiniciar el servicio siempre que se pare. Guardamos el fichero y ejecutaremos ahora:
sudo systemctl daemon-reload sudo systemctl daemon-reload
Con este comando indicaremos a systemd que debe leer de nuevo todos los ficheros de configuración de los servicios. Ya podemos reiniciar el servicio (porque lo dejamos parado antes):
sudo systemctl restart apache2.service
o
sudo service apache2 restart
Este segundo es el antiguo método, aunque systemd lo mantiene. Para comprobar que realmente funciona este método, podemos esperarnos un minuto y pedir el estado del proceso apache2, para ello ejecutamos:
sudo systemctl status apache2.service
Y veremos algo parecido a esto:
● apache2.service - The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: ena
Drop-In: /lib/systemd/system/apache2.service.d
└─apache2-systemd.conf
/etc/systemd/system/apache2.service.d
└─override.conf
Active: active (running) since Sun 2018-11-18 14:15:51 CET; 1min 19s ago
Process: 13229 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS
Main PID: 13245 (apache2)
Tasks: 55 (limit: 4915)
CGroup: /system.slice/apache2.service
├─13245 /usr/sbin/apache2 -k start
├─13248 /usr/sbin/apache2 -k start
└─13249 /usr/sbin/apache2 -k start
En la línea que comienza por Active, veremos cuánto tiempo lleva el proceso arrancado, en este caso 1 minuto y 19 segundos. Ahora, si matamos el proceso apache2 y pedimos el estado del proceso de nuevo, ahora veremos que el proceso sigue activo, pero se habrá iniciado hace unos segundos nada más. También veremos que los PID de los procesos son diferentes, y veremos una líneas indicando este reinicio.
Si queremos ver el log del proceso para saber el momento en el que se ha reiniciado, o ver directamente si se ha producido este reinicio y diagnosticarlo, porque lo ideal es que esto nunca suceda, podemos ejecutar:
sudo journalctl -u apache2.service
Ya hemos conseguido que los procesos se reinicien automáticamente, ahora vamos a afinar un poco esta configuración. Puede que nuestro servicio necesite unos segundos antes de levantarse, para lo que podremos editar el archivo de descripción del servicio e introducir:
RestartSec=2s
Y así esperaremos 2 segundos antes de reiniciarlo.
Incluso podemos limitar el número de veces que se reiniciará dentro de un intervalo de tiempo, por ejemplo, le podemos decir que si en un intervalo de 10 segundos, el servicio se reinicia 3 veces, no intentemos reiniciarlo más. Imaginemos que el equipo se queda sin disco, y vamos a tener a systemd reiniciando constantemente un servicio, ocupando CPU y memoria y puede que impidiendo la administración remota. Lo podemos hacer introduciendo estas líneas en la descripción del servicio:
StartLimitBurst=3 StartLimitIntervalSec=10
Y por supuesto, podemos probarlo matando el servicio varias veces. Incluso systemd nos indicará en el estado que ha superado el límite de reinicios y por eso el servicio se ha detenido.
Otra buena idea es, por ejemplo, enviar un correo electrónico al administrador en caso de reinicio de determinados servicios. Para ello, en esta misma descripción podemos incluir:
ExecStartPre=/usr/local/bin/correo_error_admin.pl
Luego, podemos crear el script que envía el correo, por ejemplo en Perl, introduciendo lo siguiente en el script /usr/local/bin/correo_error_admin.pl :
#!/usr/bin/perl use strict; use warnings; # first, create your message use Email::MIME; my $message = Email::MIME->create( header_str => [ From => <a href="mailto:Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.'">Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.'</a>, To => <a href="mailto:Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.'">Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.'</a>, Subject => 'Error en tu servidor', ], attributes => { encoding => 'quoted-printable', charset => 'ISO-8859-1', }, body_str => "Lo siento, tu servidor se ha reiniciado\n", ); # send the message use Email::Sender::Simple qw(sendmail); sendmail($message);
En este script podemos incluir cualquier acción que nos interese automatizar cuando se inicie el servicio. Incluso podemos utilizar ExecStartPost= para ejecutar una acción cuando el servicio se haya iniciado y de la misma manera ExecStopPre= y ExecStopPost= para ejecutar acciones cuando paremos el servicio (pero no cuando el servicio se detenga o muera).
¡Espero que les haya sido útil!
En mi último artículo hice una breve introducción a LaTeX para escritores que ahora voy a ilustar con ejemplos para aquellos que quieran ver el resultado antes de copiar y pegar el código LaTeX.
Portada de un libro:
Se define el título, el autor, la fecha... en el preámbulo y se invoca en el cuerpo del documento con \maketitle:
\documentclass[a5paper,12pt]{book}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
\title{Fuenteovejuna}
\author{Lope de Vega}
\date{1614}
\begin{document}
\maketitle
\end{document}
Resultado:
Otra opción de hacer una portada es con {titlepage} que nos ofrece mayor versatilidad a la hora de cambiar el tamaño de las letras, incluso la alineación de los textos:
\documentclass[a5paper,12pt]{book}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
\begin{document}
\begin{titlepage}
\begin{center}
\begin{Huge}
Fuenteovejuna \\
\end{Huge}
\begin{large}
Lope de Vega \\
\end{large}
\end{center}
\begin{flushright}
\begin{small}
1614
\end{small}
\end{flushright}
\end{titlepage}
\end{document}
Cuyo resultado sería:
Como ya comentaba en el anterior artículo sobre LaTeX, el resumen no vale para libros, sí para artículos o proyectos:
\documentclass[a5paper,12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
\begin{document}
\begin{abstract}
Breve introducción a LaTeX para escritores en el que se ven las principales instrucciones de LaTeX para editar libros y poder exportarlos a otros formatos.
\end{abstract}
\end{document}
Genera:
\documentclass[a5paper,12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
\begin{document}
\section{''El mundo ordinario''}
En el que se presentan los personajes y su entorno
\section{''Llamada a la aventura''} El protagonista debe actuar en algo
\section{''Rechazo de la llamada''}
El protagonista prefiere mantenerse en su mundo ordinario
\section{''Travesía del umbral''}
Comienza la aventura
\end{document}
Que genera esto:
Una de las ventajas de LaTeX es que añadir un nuevo capítulo no necesita una nueva numeración. Los numera automáticamente.
\documentclass[a5paper,12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
\begin{document}
\section{''El mundo ordinario''}
En el que se presentan los personajes y su entorno
\section{''Llamada a la aventura''}
El protagonista debe actuar en algo
\section{''Rechazo de la llamada''}
El protagonista prefiere mantenerse en su mundo ordinario
\section{''Encuentro con el mentor''}
Alguien influye en el protagonista para que acepte el reto
\section{''Travesía del umbral''}
Comienza la aventura
\end{document}
Como vemos, numera sin tener que añadir nada más que el nuevo capítulo:
Vamos a poner en las páginas impares "Aprendiendo LaTeX" "Linux Center"
y en las páginas pares "Linux Center" "Aprendiendo LaTeX"
En todas, en el pie, el número de página:
[code]
\documentclass[a5paper,12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[RO,LE]{Aprendiendo \LaTeX}
\fancyhead[LO,RE]{Linux Center}
\fancyfoot[FO,FE]{\thepage}
\begin{document}
\section{Cabecera y pie de página}
\end{document}
[/code]
Que nos daría un resultado como:
Alineación de los textos
[code]
\documentclass[a5paper,12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[RO,LE]{Aprendiendo \LaTeX}
\fancyhead[LO,RE]{Linux Center}
\fancyfoot[FO,FE]{\thepage}
\begin{document}
\section*{Alineación}
\begin{center}
Este texto está centrado
\end{center}
\begin{flushleft}
Este texto está alineado a la izquierda
\end{flushleft}
\begin{flushright}
Este texto está alineado a la derecha
\end{flushright}
\end{document}
[code]
\documentclass[a5paper,12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[RO,LE]{Aprendiendo \LaTeX}
\fancyhead[LO,RE]{Linux Center}
\fancyfoot[FO,FE]{\thepage}
\begin{document}
\section*{Anotaciones a pie de página}
Fernando Lázaro Carreter \footnote{Zaragoza, 13 de abril de 1923 – Madrid, 4 de marzo de 2004} escribió <>.
\end{document}
[/code]
Se indica en el preámbulo:
\usepackage{multicol}
\setlength\columnseprule{0.5pt}
Y en el cuerpo:
\begin{multicols}{3}
Texto
\end{multicols}
Aprovecho para explicar otro concepto: colocar un texto en apaisado, aquí me viene bien para no cortar los versos en las columnas.
Forma parte del paquete lscape, por lo que tendremos que añadir en el preámbulo:
\usepackage{lscape}
Y en el cuerpo delimitaremos con:
\begin{landscape}
\end{landscape}
Nos quedaría un código así:
[code]
\documentclass[a4paper,12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[RO,LE]{Aprendiendo \LaTeX}
\fancyhead[LO,RE]{Linux Center}
\fancyfoot[FO,FE]{\thepage}
\usepackage{lscape}
\usepackage{multicol}
\setlength\columnseprule{0.5pt}
\begin{document}
\begin{landscape}
\section*{Varias columnas}
\begin{multicols}{2}
\begin{verse}
\begin{center}
Luis de Góngora
\end{center}
Anacreonte español, no hay quien os tope,
que no diga con mucha cortesía,
que ya que vuestros pies son de elegía,
que vuestras suavidades son de arrope.
¿No imitaréis al terenciano Lope,
que al de Belerofonte cada día
sobre zuecos de cómica poesía
se calza espuelas, y le da un galope?
Con cuidado especial vuestros antojos
dicen que quieren traducir al griego,
no habiéndolo mirado vuestros ojos.
Prestádselos un rato a mi ojo ciego,
porque a luz saque ciertos versos flojos,
y entenderéis cualquier gregüesco luego.
\end{verse}
\columnbreak
\begin{center}
Francisco de Quevedo
\end{center}
\begin{verse}
Érase un hombre a una nariz pegado,
érase una nariz superlativa,
érase una alquitara medio viva,
érase un peje espada mal barbado;
Era un reloj de sol mal encarado.
érase un elefante boca arriba,
érase una nariz sayón y escriba,
un Ovidio Nasón mal narigado.
Érase el espolón de una galera,
érase una pirámide de Egito,
las doce tribus de narices era;
Érase un naricísimo infinito,
frisón archinariz, caratulera,
sabañón garrafal morado y frito.
\end{verse}
\end{multicols}
\end{landscape}
\end{document}
[/code]
Y el resultado sería:
Si lo queremos ver mejor:
Con motivo del NaNoWriMo mucha gente está en este momento en plena ebullición creativa y escritora y por eso quiero explicar unas nociones de LaTeX orientado a escritores, ya que cuando un texto está escrito, reescrito, corregido ortotipográficamente, reescrito, revisado por otras personas, reescrito, corregido el estilo, reescrito... y reescrito unas cuantas veces más, el siguiente paso es compartirlo con más gente, bien mandando el manuscrito a otras personas para que lo lean, enviarlo a editoriales o autopublicarlo.
Y aquí es cuando llega el primer problema, ¿en qué formato mandarlo y cómo editarlo?
El mundo editorial es amplísimo y cada editorial selecciona los formatos de recepción de manuscritos que desea, por lo que lo mejor es maquetar el libro de tal manera que el cambio entre formatos sea lo más sencillo posible.
Y si amplio es el mundo editorial, mucho más amplio es el mercado, por lo que aquí no hay duda alguna: hay que publicar y compartir los contenidos en formatos que pueda leer el mayor número de personas: mobi, epub, pdf, ps, html...
Para poder convertir un texto a distintos formatos de una manera sencilla, rápida y con garantías de que en la transformación de formato no va a haber una transformación de la maquetación, lo mejor es editarlo en LaTeX o en html y luego exportarlo a otros formatos.
En este artículo hablaré de LaTeX para escritores y en otro artículo haré lo mismo con html. Y ustedes elijan en qué formato maquetar sus textos.
LaTeX es un sistema de composición de textos que se basa en instrucciones independientes del texto, es decir, por un lado escribimos el texto y por otro le damos el formato.
De hecho, yo siempre lo hago así, tanto con LaTeX como con html. Primero escribo el texto y luego le doy formato.
Otra ventaja de usar LaTeX es que podemos usar cualquier editor de texto:
Es necesario un compilador de LaTeX, en GNU/Linux tenemos TexLive, que se puede instalar en modo básico:
sudo apt-get install texlive-base
o la versión completa:
sudo apt-get install texlive-full
Nunca he usado la versión básica por lo que me centraré en la completa. LaTeX es software libre y hay versiones para otros sistemas operativos. Una búsqueda en Google devolverá qué programas se pueden usar en otros sistemas distintos a GNU/Linux.
Desde la consola:pdflatex fichero.tex
O también podemos usar un programa mucho más genérico: pandoc
pandoc -s original.tex -o fichero.extension
Pandoc es como convert, simplemente indicándole la extensión del fichero de salida le da ese formato.
Visto cómo crear el entorno de trabajo para editar con LaTeX, pasemos a lo divertido: maquetar un texto.
Para ello, abrimos nuestro editor de texto favorito con el texto a maquetar, a poder ser en texto plano, y vamos a darle formato.
Veamos un ejemplo muy sencillo de uso:
Abrimos vi, o cualquier otro editor de textos, y escribimos:\documentclass{article}
\begin{document}
¡Hola, mundo!
Este es mi primer texto con \LaTeX{}.
Estoy feliz^2: feliz por usar \LaTeX{} y feliz por compartirlo con ustedes.
Pero no sé si esta frase se verá bien. Estoy usando tildes y eso me puede hacer la puñeta.
\end{document}
Guardamos como holamundo.tex, o el_nombre_que_queramos.tex, y ejecutamos:pdflatex holamundo.tex
Y nos saldrá esto:
No se ve bien, así que vamos a mejorarlo:\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
\begin{document}
¡Hola, mundo!
Este es mi primer texto con \LaTeX{}.
\pre
Estoy feliz^2:\newline
\textrm{feliz por usar \LaTeX{}} \newline
\textrm{y feliz por compartirlo con ustedes.}\newline
\pre
\textrm{Pero no sé si esta frase se verá bien. Estoy usando tildes y eso me puede hacer la puñeta.}
\end{document}
Ahora nos mostrará el texto bien formateado:
El ejemplo anterior era muy sencillo, pero vemos dos partes diferenciadas, primero le decimos que el tipo de documento es un artículo y luego trabajamos con el texto.
En LaTeX estas partes se conocen como preámbulo y documento.
En LaTeX primero de todo hay que indicar el tipo de documento. Esto se hace con
\documentclass{tipo_de_documento}
Fundamentalmente hay tres tipos de clases de documentos:
article: artículos, textos cortos
report: se suele usar para proyectos
book: libros
Aunque hay más tipos, como letter para cartas, pero una carta bien se podría maquetar como "article".
Aquí le podemos indicar formato de la página. Bien si queremos un formato estándar como pueda ser DIN A4, DIN A5... o si queremos un tamaño especial y el tamaño de la letra. Es muy importante si vamos a maquetar un libro, elegir bien el tamaño del soporte sobre el que queremos que se lea el texto. Y que el tamaño de la letra sea el adecuado.
Luego según qué formato, el usuario podrá ampliar o reducir el tamaño de la letra o cambiar el tamaño del documento, pero eso es cuestión del usuario.
Veamos distintas formas de seleccionar el tamaño del documento.
Formato estándar:
\documentclass[a4paper,10pt]{article}
En el tamaño del papel le podemos indicar:
a4paper
a4paper
...
Si tiene una o dos caras:
oneside
twoside
En el preámbulo también podemos añadir paquetes adicionales. Por ejemplo, si escribimos en español, podemos indicar que añada paquetes con eñes, tildes, diéresis...:\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
Se define con:\renewcommand{\baselinestretch}{factor_de_interlineado}
Donde podemos indicar un número decimal como factor de interlineado.
De esta forma no tendremos que editar a mano cada vez que queramos que se muestre una tilde ni que nos pase como en el primer ejemplo.
Una vez definido el preámbulo, pasamos a la edición del texto, que será lo que compilará LaTeX al transformar el fichero .tex a excepción de los comentarios, que son notas que nos podemos dejar para indicar si tenemos que revisar algo, si le dejamos apuntado algo a otra persona con la que estamos editando el texto o cualquier anotación que no queramos que se muestre en el documento final.
% Esto es un comentario, ya que va con un signo de porcentaje delante
\begin{document}
Este es el texto del documento. Todo lo que vaya después del end no será procesado. Pero lo que esté entre begin y end, sí será procesado. \end{document}
\title{Aquí escribo mi título}
\author{Nombre del autor}
\date{Fecha de edición}
El bloque abstract sólo funciona en report y article, no en book.
Esto vale:
\begin{abstract}
Breve introducción a LaTeX para escritores en el que se ven las principales instrucciones de LaTeX para editar libros y poder exportarlos a otros formatos.
\end{abstract}
Esto no vale:
\begin{abstract}
Este es el resumen del libro en el que unos personajes están en un lugar y les ocurren cosas.
\end{abstract}
Cualquier libro puede tener capítulos, secciones, subsecciones, subsecciones de las subsecciones, párrafos, subpárrafos... Veamos sus instrucciones
\chapter{Título del capítulo}
\section{Título de la sección}
\subsection{Título de la subsección}
\subsubsection{Título de la subsección de la subsección}
\paragraph{Título del párrafo}
\subparagraph{Título del subpárrafo}
Estas instrucciones numeran automáticamente las secciones, subsecciones, los capítulos... por lo que no hace falta indicar la numeración y añadir una nueva instrucción supone que se renumeran automáticamente.
Si queremos que algún apartado no esté numerado se le indica al compilador con un asterisco entre la instrucción y el corchete de apertura del título:\chapter*{Título no numerado de un capítulo}
Se define con \pagestyle y puede tener los siguientes valores:
empty: vacía, no tiene ni cabecera ni pie de página
plain: cabecera vacía, numeración de página al pie.
headings: cabecera con el título de los capítulos y las secciones
myheadings: texto definido por el usuario
Si se usa
\pagestyle{myheadings}
Se define el texto a mostrar con:
\markboth{Texto alineado a la izquierda}{Texto alineado a la derecha}
Se definen con:
\pagenumbering{formato_de_numeración}
Que suelen tener los siguientes valores:
arabic -> numeración árabe del 0 al 9
Roman -> numeración romana en mayúsculas. Si se quiere en minúsculas, es roman
Alph -> numeración alfabética de la A a la Z mayúsculas. Si se quiere en minúsculas, es alph
Se puede cambiar el formato de tipo de letra con:
\textrm{Texto en letra redonda}
\textit{Texto en cursiva}
\texttt{Texto con tipografía de máquina de escribir}
\textbf{Texto en negrita}
Los tamaños de las letras también se puede modificar, dejo la lista por orden de la más pequeña a la más grande. Nótese que tanto la instrucción como el texto va entre llaves:
{\tiny Texto}
{\scriptsize Texto}
{\footnotesize Texto}
{\small Texto}
{\large Texto}
{\Large Texto}
{\LARGE Texto}
{\huge Texto}
{\Huge Texto}
\begin{center}
Este texto está centrado
\end{center}
\begin{flushleft}
Este texto está alineado a la izquierda
\end{flushleft}
\begin{flushright}
Este texto está alineado a la derecha
\end{flushright}
Para maquetar poemas en LaTeX está el bloque "verse" que acota el comienzo y el final del poema. Los versos se separan con \\\begin{verse}
\begin{center}
Escritura
\end{center}
Mi psicólogo mide doce centimientros\\
y vive en un estuche \\
terapias de papel y tinta \\
si la vida es pasajera mis palabras infinitas \\
abro el bloc pronto por la mañana \\
cuando la pizarra de la menta \\
aun no ha sido emborronada \\
por los sucesos de la jornada \\
\begin{flushright}
Xhelazz
\end{flushright}
\end{verse}
Nos daría un resultado así:
\footnote{Esto es una nota al pie de página}
Para hacer un salto de párrafo tenemos dos opciones:
Dejar una línea en blanco entre párrafo y párrafo
Usar la instrucción \par
Por defecto LaTeX sangra la primera línea de un párrafo. Para evitarlo:\noindent
\newline
Aquí no voy a poner más que unos pocos caracteres especiales que puedan usarse de forma más o menos habitual por parte de escritores, que es el público objetivo de este artículo, aunque LaTeX permita trabajar con fórmulas matemáticas, no las veremos aquí.
^ Superíndice. Por ejemplo: E=mc^2
_ Subíndice. Por ejemplo: H_2O
Aunque añadiendo los paquetes:\usepackage[utf8]{inputenc}
\usepackage[activeacute,spanish]{babel}
no necesitaríamos indicar a LaTeX que una letra lleva tilde o es eñe, dejo aquí los códigos por si alguien los necesitase o no pudiese usar paquetes adicionales:
\’a -> á
\’e -> é
\’i -> í
\’o -> ó
\’u -> ú
\’A -> Á
\’E -> É
\’I -> Í
\’O -> Ó
\’U -> Ú
̃
\~n -> ñ
\~N -> Ñ
Para escribir comillas españolas o latinas, se escribe menor que menor que, el texto a entrecomillar, mayor que mayor que y LaTeX lo transforma a las dobles comillas españolas:
<<Este texto está entre comillas españolas>>
Resultado:
Aunque esto es más habitual en periódicos o revistas, también podemos querer maquetar nuestro libro en varias columnas. Para eso usaremos el paqute multicol y definiremos la separación entre las columnas con columnseprule, después en el texto indicaremos el número de columnas:\usepackage{multicol}
\setlength\columnseprule{0.5pt}
\begin{document}
\begin{multicols}{3}
\blindtext
\end{multicols}
\begin{thebibliography}{00}
\bibitem{1}
Primera referencia
\bibitem{2}
Segunda referencia
\bibitem{3}
Tercera referencia
\end{thebibliography}
Bash nos permite hacer millones de cosas. Es más, como nos permite hacer llamadas a otros programas, colocando las entradas y salidas adecuadas podremos producir cualquier resultado. Nos viene muy bien poder encadenar varios comandos, como en este tutorial en el que la salida de echo la pasamos como entrada de tr. Pero en este tutorial quiero hablar de operaciones que podemos hacer directamente en Bash, sin ningún programa extra o dependencia. Además, su realización será mucho más rápida ya que no tenemos que cargar en memoria un programa. Esto nos resultará de gran ayuda si utilizamos sistemas empotrados como Raspberry PI, o cualquier dispositivo con chips o almacenamiento reducidos.
Eso sí, para muchos ejemplos necesitaremos Bash 4.x (aunque ya tiene unos años, la versión salió en 2009)
¡Manos a la obra!
Aunque existen herramientas como sed o awk que, no estoy diciendo que no las usemos, porque son herramientas muy potentes. Cuando se trata de hacer un simple reemplazo de un texto por otro dentro de un texto más grande. O lo que es lo mismo, reemplazar subcadenas dentro de una cadena, podemos hacer lo siguiente:
texto="Los mejores tutoriales sobre Windows en WindowsCenter" echo ${texto//Windows/Linux}
La clave está en tener el texto en una variable y luego hacer
echo ${VARIABLE//Cadena a buscar/Cadena que reemplaza}
O también podemos hacer lo siguiente:
texto="No hables de Linux en LinuxCenter" echo ${texto/Linux/Windows}
Fijaos que ahora solo hay una barra (/) en lugar de dos. Con las sustituciones podemos hacer muchas cosas, incluso utilizar expresiones regulares.
Es muy común hacer lo siguiente:
texto="cadena de caracteres muy muy larga" echo $texto | wc -m
Pero podemos hacerlo sin llamar a wc (cuidado, también podemos utilizar -c, pero tendremos problemas con caracteres especiales) de la siguiente manera:
texto="cadena de caracteres muy muy larga" echo ${#texto}
Una nota, si comparáis los dos resultados, saldrán distintos, el primer método tendrá un carácter más. Eso es porque contamos el "intro" o mejor dicho, el retorno de carro, cuando utilizamos la primera forma. También podríamos hacerlo así:
texto="cadena de caracteres muy muy larga" echo -n $texto | wc -m
¿Qué ocurre si queremos sacar una subcadena dentro del texto? Por ejemplo, tenemos esta cadena de texto:"Los mejores tutoriales sobre Linux en LinuxCenter"
Y queremos extraer 10 letras desde el carácter número 12, podemos hacer:
texto="Los mejores tutoriales sobre Linux en LinuxCenter" echo ${texto:12:10}
O si queremos sacar desde el carácter 37 hasta el final, podemos hacer:
texto="Los mejores tutoriales sobre Linux en LinuxCenter" echo ${texto:37}
Si tengo este texto: "Esto es un pequeño tutorial de Linux en el que hablo de Bash."
Y quiero saber si una subcadena está presente, puedo hacer lo siguiente:
texto="Esto es un pequeño tutorial de Linux en el que hablo de Bash." if [[ "$texto" == *"Windows"* ]]; then echo "ESTÁ"; else echo "NO ESTÁ"; fi
Si tenemos un nombre de archivo con la ruta completa y queremos extraer el directorio donde está localizado el fichero podemos hacer lo siguiente:
fichero="/usr/share/icons/hicolor/64x64/mimetypes/libreoffice-oasis-data.png" echo "${fichero%/*}"
En este caso obtendremos: /usr/share/icons/hicolor/64x64/mimetypes/ . En teoría estamos eliminando de la cadena desde el final hasta la última / y devolvemos lo que nos queda. Al final obtenemos lo mismo que haciendo:
dirname /usr/share/icons/hicolor/64x64/mimetypes/libreoffice-oasis-data.png
Ahora si lo que queremos es sacar el nombre de archivo libreoffice-oasis-data.png sin la ruta, igual que hacemos con el comando basename. Podemos hacer:
fichero="/usr/share/icons/hicolor/64x64/mimetypes/libreoffice-oasis-data.png" echo "${fichero##*/}"
En este caso, eliminamos todos los caracteres desde el principio hasta la última / que encontramos.
De la misma forma que hicimos para sacar la ruta del archivo, vamos a extraer la extensión de un archivo, de la siguiente manera:
fichero="/home/usuario/backups/2018_11_13.tar.gz" echo "${fichero%%.*}"
Ahora queremos quedarnos con la extensión, para ello, propongo dos casos. En el primero, sacaremos todo lo que hay detrás del primer punto del archivo:
fichero="/home/usuario/backups/2018_11_13.tar.gz" echo ${fichero##*.}
Aunque también puede ser que solo necesitemos la última extensión (desde el último punto hasta el final):
fichero="/home/usuario/backups/2018_11_13.tar.gz" echo ${fichero#*.}
Queremos saber en qué letra se encuentra la palabra Linux dentro de la frase "Esto es un pequeño tutorial de Linux en el que hablo de Bash." así que hacemos lo siguiente:
texto="Esto es un pequeño tutorial de Linux en el que hablo de Bash." tmp="${texto%%Linux*}" echo ${#tmp}
Si os fijáis, es parecido a lo que hacíamos para extraer el nombre de archivo (solo que ahora en lugar de un punto, buscamos la palabra Linux, y luego contamos las letras de la cadena temporal generada. Incluso la palabra a buscar puede ser otra variable. Eso sí, tendremos un problema cuando la palabra no exista, que nos devolverá la posición del final de la cadena, entonces podemos hacer lo siguiente:
busca="Linux"texto="Esto es un pequeño tutorial de Linux en el que hablo de Bash." tmp="${texto%%$busca*}" [[ "$texto" = "$tmp" ]] && echo -1 || echo ${#tmp}
Con lo que si el texto no se encuentra, devuelve -1
Por último, quiero dejaros para copiar y pegar todo esto en forma de funciones para poder incorporar fácilmente a vuestros scripts estas utilidades:
#!/bin/bash function replace() { local text="$1" local busc="$2" local repl="$3" echo ${text//$busc/$repl} } function replace_once() { local text="$1" local busc="$2" local repl="$3" echo ${text/$busc/$repl} } function longitud() { local text="$1" echo ${#text} } function recorta() { local text="$1" local desde=$2 local hasta=$3 [ -z $hasta ] && echo ${text:$desde} || echo ${text:$desde:$hasta} } function encuentra() { local text="$1" local subt="$2" [[ "$texto" == *"Windows"* ]] && true || false } function ruta_archivo() { local fich="$1" echo "${fich%/*}" } function base_archivo() { local fich="$1" echo "${fich##*/}" } function extension_archivo() { local fich="$1" echo ${fich##*.} } function extension_archivo2() { local fich="$1" echo ${fich#*.} } function posicion_cadena() { local text="$1" local subc="$2" tmp="${text%%$subc*}" [[ "$texto" = "$tmp" ]] && echo -1 || echo ${#tmp} }
Ahora Probamos las funciones
replace "I love Windows, forever Windows" "Windows" "Linux"replace "I love Windows, forever Windows" "Windows" "Linux" replace_once "I love Windows. Windows never closes unexpectedly" "Windows" "Linux" longitud "Esta es una cadena muy larga que no se cuantas letras contiene" recorta "Desde que uso GNU/Linux soy más feliz" 14 9 recorta "Desde que uso GNU/Linux soy más feliz" 24 if encuentra "$(uname)" "Linux"; then echo "Buen sistema el tuyo!"; fi ruta_archivo "/home/usuario/proyectos/github/tutoriales/cadenas_bash.txt" base_archivo "/home/usuario/proyectos/github/tutoriales/cadenas_bash.txt" extension_archivo "/home/usuario/proyectos/github/tutoriales/cadenas_bash.tar.bz2" extension_archivo2 "/home/usuario/proyectos/github/tutoriales/cadenas_bash.tar.bz2" posicion_cadena "No sé dónde está Linux en todo este texto" "Linux"
¡Espero que les haya sido útil!
En Kdenlive 17 han cambiado la ubicación de algunas funciones en los menús. Y algunas han desaparecido, como la de invertir los clips. Por extrapolación de cómo se hace en otros programas he deducido la solución que os comparto:
Sobre el clip que se desea invertir, botón derecho / Agregar efecto / Moviemiento / Velocidad. Y le damos una velocidad negativa al clip.
Si queremos un vídeo que siga el orden normal y otro que vaya hacia atrás, lo que podemos hacer es sobre el fichero en la carpeta del proyecto: botón derecho / Trabajos del clip / Duplicar el clip con cambio de velocidad. Y le damos una velocidad negativa al clip.
Para girar o rotar una imagen con ImageMagick tenemos el parámetro -rotate que debe ir seguido por los grados de rotación a girar la imagen.
Veamos un ejemplo. Primero, creamos una imagen:
convert -size 250x250 xc:Blue cuadroazul.png
Y una vez que tenemos la imagen, lo podemos rotar:
convert cuadroazul.png -rotate 45 cuadroazul-rotado.png
Al rotar una imagen nos podemos encontrar con dos problemas, pero para ambos problemas hay solución:
que nos podemos encontrar que el color de fondo no nos guste, que se soluciona con -background
que el resultado sea una imagen con un tamaño que nos descuadre el resto de la composición, que se soluciona con -extent
Veamos los dos con ejemplos. Primero, el color de fondo:
convert cuadroazul.png -background Red -rotate 45 cuadroazul-rotado-confondorojo.png
convert cuadroazul.png -background Red -rotate 45 -extent 250x250 cuadroazul-rotado-confondorojo-ajustado.png
convert cuadroazul.png -background Red -rotate 45 -gravity Center -extent 250x250 cuadroazul-rotado-confondorojo-ajustado-centrado.png
convert -size 500x500 xc:GhostWhite -background NavajoWhite -rotate 45 -gravity NorthEast -extent 1000x1000 cuadroblancosobrefondoblanco-imagemagick.png
Uno de los primeros artículos que escribí en Linux Center sobre ImageMagick versaba sobre cómo generar lienzos simples en ImageMagick.
Ahora, después de haber publicado unos cuantos artículos más sobre ImageMagick me parece un buen momento para hacer una recopilación de las distintas formas de hacer un lienzo y cómo aplicarle efectos para poder generar multitud de imágenes distintas como fondo de escritorio, fondos para escribir textos en redes sociales y llamar así más la atención de los destinatarios, imágenes para WhatsAPP / Telegram... y de paso, ver también cómo construir instrucciones complejas en ImageMagick.
Para generar imágenes con ImageMagick el comando a usar es convert, al cual le tenemos que indicar el tamaño de la imagen con -size, el color a usar con xc: y el nombre de la imagen a generar.
La estructura más sencilla para generar una imagen con ImageMagick sería algo así:
convert -size 500x100 xc:Black franjanegra.png
Podríamos combinar en la misma instrucción varias veces el parámetro xc: con atención a que si no añadimos más parámetros, convert generará tantos ficheros como imágenes generadas con xc:
convert -size 500x100 xc:Black xc:Red xc:Blue franjanegra.png
Generará tres ficheros:
franjanegra-0.png
franjanegra-1.png
franjanegra-2.png
Si queremos que esos lienzos formen parte de un único fichero unido verticalmente necesitamos usar el parámetro append. Con -append la unión será vertical y con +append la unión será horzontal.
convert -size 500x100 xc:Black xc:Red xc:Blue -append tresfranjas.png
Como hemos visto hasta aquí, si únicamente utilizamos un -size, todas las piezas medirán lo mismo. Veamos cómo hacer una imagen con piezas de distintos tamaños. Y de paso, veamos cómo concatenar imágenes en formato horizontal (con +append):
convert -size 100x500 xc:Black -size 200x500 xc:Red -size 300x500 xc:Blue +append tresfranjasverticales.png
A los lienzos generados se les puede añadir nuevos parámetros. Por ejemplo -border que añade un borde al lienzo del color indicado con -bordercolor:
convert -size 300x300 xc:Red -bordercolor Black -border 100x100 negroborderojo.png
Los gradientes de color o degradados básicos que se pueden hacer en ImageMagick son lineales o radiales, con los parámetros gradient: y radial-gradient: en lugar de xc:
convert -size 500x500 gradient:Red-Blue degradadorojoazul.png
convert -size 500x500 radial-gradient:Red-Blue degradadoradialrojoazul.png
Una vez visto este recordatorio, aquí empezamos con la elaboración de instrucciones complejas en ImageMagick.
Los degradados lineales realizados con gradient no permiten grandes posibildades de adaptación, pero podemos unir parámetros, como xc: y gradient: para poder hacer imágenes en el que haya partes sin degradados:
convert -size 500x100 xc:Red -size 500x300 gradient:Red-Blue -size 500x100 xc:Blue -append unionxcgradient.png
Vamos a rizar un poco más el rizo y vamos a unir un parámetro más, el parámetro rotate para girar la imagen y que el degradado tenga formato horizontal:
convert -size 500x100 xc:Red -size 500x300 gradient:Red-Blue -size 500x100 xc:Blue -append -rotate 90 unionxcgradientgirado.png
Podemos encadenar distintos gradientes y lienzos lisos, tantos como queramos, aquí uniremos dos degradados con un lienzo liso a modo de ejemplo:
convert -size 500x200 gradient:Red-Blue -size 500x100 xc:Blue -size 500x200 gradient:Blue-Red -append doblegradiente.png
A los lienzos creados, podemos aplicarles un difuminado posterior para que haga el efecto de degradado
convert -size 500x250 xc:Blue xc:Red -append -blur 0x250 difuminadoblur.png
Y aquí viene un punto muy importante que quiero remarcar:
ImageMagick procesa los parámetros de izquierda a derecha, así que para que pueda generarse el difuminado en la unión de los dos lienzos es necesario que el parámetro -append esté antes del parámetro -blur.
A convert se le puede indicar que haga degradados en direcciones concretas. Tanto lineales como radiales. Veamos esta última opción con distintos grados aplicados como valor al parámetro -radial-blur ya que es más sencillo ver el resultado en una imagen que leer su descripción:
convert -size 500x250 xc:Blue xc:Red -append -radial-blur 45 difuminadoradialblur-45.png
convert -size 500x250 xc:Blue xc:Red -append -radial-blur 90 difuminadoradialblur-90.png
convert -size 500x250 xc:Blue xc:Red -append -radial-blur 135 difuminadoradialblur-135.png
convert -size 500x250 xc:Blue xc:Red -append -radial-blur 180 difuminadoradialblur-180.png
convert -size 500x250 xc:Blue xc:Red -append -radial-blur 225 difuminadoradialblur-225.png
convert -size 500x250 xc:Blue xc:Red -append -radial-blur 270 difuminadoradialblur-270.png
convert -size 500x250 xc:Blue xc:Red -append -radial-blur 315 difuminadoradialblur-315.png
convert -size 500x250 xc:Blue xc:Red -append -radial-blur 360 difuminadoradialblur-360.png
Vista la evolución de -radial-blur, veamos lo mismo con -motion-blur, que cuenta con tres parámetros: $radioX$sigma+$ángulo
convert -size 500x250 xc:Blue xc:Red -append -motion-blur 0x100+45 difuminadomotionblur-45.png
convert -size 500x250 xc:Blue xc:Red -append -motion-blur 0x100+90 difuminadomotionblur-90.png
convert -size 500x250 xc:Blue xc:Red -append -motion-blur 0x100+135 difuminadomotionblur-135.png
convert -size 500x250 xc:Blue xc:Red -append -motion-blur 0x100+180 difuminadomotionblur-180.png
convert -size 500x250 xc:Blue xc:Red -append -motion-blur 0x100+225 difuminadomotionblur-225.png
convert -size 500x250 xc:Blue xc:Red -append -motion-blur 0x100+270 difuminadomotionblur-270.png
convert -size 500x250 xc:Blue xc:Red -append -motion-blur 0x100+315 difuminadomotionblur-315.png
convert -size 500x250 xc:Blue xc:Red -append -motion-blur 0x100+360 difuminadomotionblur-360.png
Sobre todo quiero que se note cómo afecta a la imagen un -motion-blur con un ángulo de 180 ó 360 grados en una imagen con dos franjas horizontales. Y ahora veamos cómo afecta el valor del ángulo tanto en -radial-blur como -motion-blur en una imagen con predominancia de un color y una forma que la cruce. Por ejemplo, una cruz de San Jorge:
convert -size 400x400 xc:White -background Red -splice 100x100+200+200 sanjorge.png
Y ahora vamos a hacer una evolución de un -motion-blur y un -radial-blur para ver cómo afecta cuando la imagen muestra una forma de cruz:
Veamos la diferencia entre -motion-blur 90 y -motion-blur 180
Y entre -motion-blur 45 y -motion-blur 135
Y en cuanto a -radial-blur, veamos como afecta con 90 y múltiplos de 90: 180, 270 y 360:
Y sin embargo, cómo afecta cuando no son mútliplos de 90:
-radial-blur 45
-radial-blur 135
-radial-blur 225
-radial-blur 315
Otra forma de modificar las imágenes y hacer menos nítidos los bordes es mediantes las dispersiones con el parámetro -spread:
convert -size 500x250 xc:Red xc:Blue -append -spread 5 rojoazul-spread5.png
[code]convert -size 500x250 xc:Red xc:Blue -append -spread 50 rojoazul-spread50.png[/code]
Incluso se puede aplicar un valor mayor al tamaño en píxeles de la altura de la imagen dando un efecto de caos total:
convet -size 500x250 xc:Red xc:Blue -append -spread 1000 rojoazul-spread1000.png
En una imagen en el que no están definidas las líneas, sí que afecta el -motion-blur con 180 y 360:
[code]convert -size 500x250 xc:Red xc:Blue -append -spread 1000 -motion-blur 0x100+180 rojoazul-spread1000-motion-blur180.png[/code]
convert -size 500x250 xc:Red xc:Blue -append -spread 1000 -motion-blur 0x100+360 rojoazul-spread1000-motion-blur360.png
convert -size 500x250 xc:Red xc:Blue -append -spread 1000 -radial-blur 90 rojoazul-spread1000-radial-blur90.png
convert -size 500x250 xc:Red xc:Blue -append -spread 1000 -radial-blur 360 rojoazul-spread1000-radial-blur360.png
convert -size 500x250 xc:Red xc:Blue -append -radial-blur 360 -spread 1000 rojoazul-radial-blur360-spread1000.png
[code]convert -size 500x250 xc:Red xc:Blue -append -radial-blur 360 rojoazul-radial-blur360-sin-spread.png[/code]
En el anterior artículo contaba cómo pasar cadenas de texto a mayúsculas, a minúsculas o todas en minúsculas excepto la primera letra, que esa sí que pasaría, en caso de que no lo estuviera, a mayúsculas (por ejemplo para escribir nombres propios).
Aquí dejo otra pildorita sobre tr, cómo eliminar los espacios en blanco de una variable:
#!/bin/bash variable="Esto es una cadena de texto con espacios en blanco" sinespacios=$(echo "$variable" | tr -d '[[:space:]]') echo $sinespacios
Al ejecutar este script, la salida será:
Estoesunacadenadetextoconespaciosenblanco
Para transformar caracteres, bien para borrarlos o bien para modificarlos en GNU/Linux tenemos el comando tr, que cuenta con una serie de filtros para procesar en bloque cadenas de texto. En este artículo veremos dos de ellos: [:lower:] y [:upper:]
En la consola:
variable="LINUXCENTER"; echo $variable | tr '[:upper:]' '[:lower:]'
que devuelve:
linuxcenter
Todos los carecteres que recibe tr en mayúsculas ('[:upper:]') a mayúsculas ('[:lower:]')
En un script:
variable="LINUXCENTER" minusculas=$(echo $variable | tr '[:upper:]' '[:lower:]')
En consola:
variable="linuxcenter"; echo $variable | tr '[:lower:]' '[:upper:]'
Que devuelve:
LINUXCENTER
Ya que todos los caracteres que recibe tr en minúsculas ('[:lower:]') lo transforma en mayúsculas ([:upper:])
En un script:
variable="linuxcenter" mayusculas=$(echo $variable | tr '[:lower:]' '[:upper:]')
En consola:
variable="linuxcenter"; echo -n ${variable:0:1} | tr '[:lower:]' '[:upper:]'; echo ${variable:1} | tr '[:upper:]' '[:lower:]'
Que devuelve:
Linuxcenter
Veamos qué hace esta línea:
variable="linuxcenter"; -> Le damos un valor cualquiera a una variable.
echo -n ${variable:0:1} | tr '[:lower:]' '[:upper:]'; -> -n indica a echo que no envíe el salto de línea al final de la cadena que va a mostrar. ${variable:0:1} indica que extraiga desde la posición 0 un caracter y que lo pase a tr. Si está en minúscula, pasará el caracter a mayúscula.
echo ${variable:1} | tr '[:upper:]' '[:lower:]' -> ${variable:1} extrae la subcadena contenida en la variable $variable que va desde la posición 1 hasta el final.
Y en un script:
variable="linuxcenter" conmayuscula=$(echo -n ${variable:0:1} | tr '[:lower:]' '[:upper:]'; echo ${variable:1} | tr '[:upper:]' '[:lower:]')