¿Hacemos una Webserie?

¿Hacemos una Webserie?

Cuando usando una aplicación nos autocompleta el texto, nos subraya una palabra o nos dice que algo está incorrectamente escrito, no es magia, es que esa aplicación hace uso de un diccionario.

Aunque hay aplicaciones que tienen diccionarios propios, el sistema también tiene al menos uno genérico del que podemos hacer uso o podemos usarlo como base para añadirle nuevas palabras.

En Ubuntu, este diccionario está en:

/usr/share/dict/spanish

Pero no necesariamente todas las distribuciones tienen por qué guardar el diccionario de español en esa dirección, por lo que podemos buscar en nuestro sistema con:

find /usr -iname spanish | grep dict

Y nos dirá la dirección en el arbol de directorios del sistema de nuestro diccionario.

diccionario.png

Ya sabemos cómo seleccionar aleatoriamente una tipografía para incluir texto en ImageMagick, pero nos puede ocurrir que, al ser aleatoria esa selección, nos elija una tipografía que sean dibujos, signos matemáticos o cualquier otra tipografía que no sea de letras, también nos puede mostrar una tipografía con un alfabeto distinto al nuestro o que no muestre bien algunos caracteres.

Yo siempre me fijo en cuatro caracteres clave: apertura de interrogación y exclamación, vocales con tilde y eñes.

Así pues, voy a usar una cadena de caracteres que tenga interrogaciones, una vocal con tilde y una eñe:

¿Leña? ¡Porrón!

Y como quiero ver qué tipografías que tengo instaladas en cada máquina muestran correctamente estos caracteres, hago los siguientes pasos:

  1. Utilizo un script que escribe la cadena "¿Leña? ¡Porrón!" con todas las tipografías instaladas en ese sistema.
  2. Compruebo las tipografías que muestran bien esos caracteres y además son legibles y cubren mis necesidades para escribir automáticamente sin miedo a que por automatizar se vea mal el texto. Y borro lo que me sobra.
  3. Un segundo script recoge las tipografías "supervivientes" que cumplen mis necesidades y genera una lista con esas tipografías
  4. Selecciono aleatoriamente de ese listado las tipografías para escribir en las imágenes

Script compruebatipografias.sh

#!/bin/bash

directoriotemporaltipografias="tipografias"

if [ ! -d directoriotemporaltipografias ]
then
    mkdir $directoriotemporaltipografias
fi

for tipografia in $(convert -list font | grep "Font" | cut -d " " -f 4)
do
    convert -pointsize 100 -font $tipografia label:"¿Leña? ¡Porrón!" $directoriotemporaltipografias/$tipografia.jpg
done

Veamos qué es lo que hace:

Indico que es un script en bash:

#!/bin/bash

Que el directorio con el que voy a trabajar se llama "tipografias", pero lo meto en una variable por si por cualquier motivo quiero cambiar de directorio:


directoriotemporaltipografias="tipografias"

 

Compruebo si existe o no ese directorio y si no existe, lo creo:
if [ ! -d directoriotemporaltipografias ]
then
    mkdir $directoriotemporaltipografias
fi

Hago un bucle en el que recorre todas las tipografías tal como vimos en el artículo anterior sobre tipografías en ImageMagick: y le digo que me genere una imagen por cada tipografía con la cadena antes indicada de "¿Leña? ¡Porrón!" guardando esas imágenes con el nombre de la tipografía utilizada en el directorio creado para tal efecto:
for tipografia in $(convert -list font | grep "Font" | cut -d " " -f 4)
do
    convert -pointsize 100 -font $tipografia label:"¿Leña? ¡Porrón!" $directoriotemporaltipografias/$tipografia.jpg
done

Selección manual de las tipografías

 

Con esto, tengo un directorio lleno de imágenes con cadenas de texto. Abro el directorio con un navegador de ficheros que muestre una previsualización de cada imagen y selecciono todas las imágenes que no me interesan por el motivo que sea, que generalmente es porque no escribe bien todos los caracteres indicados:

selecciondetipografias.png

 

Otras veces es porque, aunque muestre correctamente los caracteres, no me parecen lo suficientemente legibles o son muy específicos de una determinada fecha: navideños, de Hallowen, con nieve...

Una vez borrados los que en una primera ronda en bruto me han parecido que no cubren mis necesidades (ojo, que cuando seleccionamos aleatoriamente una tipografía es bastante arriesgado poner a trabajar ese script y desentendernos, por lo que es mejor que, en caso de duda, borrar el fichero), paso a una segunda fase en la que miro una por una las tipografías.

A veces nos encontramos que una tipografía escribe correctamente los caracteres pero no nos queremos arriesgar a que un script la seleccione sin nuestra aprobación:

Capacitor.jpgEdgewater.jpg

 

Estas tipografías muestran todos los caracteres, pero quizá no encajen en todos los contextos, por lo que las borro también.

 

 

Script listatipografias.sh

Y una vez que he borrado todo lo que sobra, ejecuto un segundo script:

#!/bin/bash

directoriotemporaltipografias="tipografias"

for fichero in $(ls $directoriotemporaltipografias)
do
    echo ${fichero%.*} >> tipografiasausar.txt
done

rm -r $directoriotemporaltipografias
rmdir $directoriotemporaltipografias

 

En el que le indico:

Que es un script bash:

#!/bin/bash

Que recoja los ficheros de un determinado directorio:
directoriotemporaltipografias="tipografias"

Que recorra ese directorio fichero a fichero y quite la extensión de esos ficheros ${fichero%.*} e incluya el nombre sin extensión en un fichero de texto llamado tipografiasausar.txt añadiendo en cada pasada de for cada tipografía al texto ya existente en ese fichero (>>)
for fichero in $(ls $directoriotemporaltipografias)
do
    echo ${fichero%.*} >> tipografiasausar.txt
done

Que borre el contenido de ese directorio y el propio directorio para que no ocupe espacio en disco ni moleste una vez hecha la selección.
rm -r $directoriotemporaltipografias
rmdir $directoriotemporaltipografias

 

Uso del fichero tipografiasausar.txt

Una vez creado el fichero tipografiasausar.txt para seleccionar aleatoriamente una línea de ese fichero lo podemos hacer con shuf. Así:

tipografia=$(shuf -n 1 tipografiasausar.txt)

 

Y así quedaría un script de ejemplo:

#!/bin/bash
tipografia=$(shuf -n 1 tipografiasausar.txt)
convert -pointsize 100 -fill Blue -font $tipografia label:"Automaticen\ny sean felices" automaticen.png

 

En ImageMagick tenemos el parámetro -list que lista los valores que pueden recibir algunos parámetros.

Uno de los parámetros del que se puede listar los valores que puede recibir es font, que es el parámetro que permite seleccionar la tipografía con la que escribir un texto con annotate o label, así pues, si escribimos:

convert -list font

convert nos mostará las tipografías de nuestro sistema con una serie de datos más, como la familia, la dirección...

Font: Zoidal-BRK
    family: Zoidal BRK
    style: Normal
    stretch: Normal
    weight: 400
    glyphs: /usr/share/fonts/truetype/aenigma/zoidal.ttf
  Font: Zrnic
    family: Zrnic
    style: Normal
    stretch: Normal
    weight: 400
    glyphs: /usr/share/fonts/truetype/larabie/zrnic___.ttf
  Font: Zurklez-Outline-BRK
    family: Zurklez Outline BRK
    style: Normal
    stretch: Normal
    weight: 400
    glyphs: /usr/share/fonts/truetype/aenigma/zurklezo.ttf
  Font: Zurklez-Solid-BRK
    family: Zurklez Solid BRK
    style: Normal
    stretch: Normal
    weight: 400
    glyphs: /usr/share/fonts/truetype/aenigma/zurklezs.ttf
  Font: Æ-Systematic-TT-BRK
    family: Æ Systematic TT BRK
    style: Normal
    stretch: Normal
    weight: 400
    glyphs: /usr/share/fonts/truetype/aenigma/aesymatt.ttf
  Font: Ænigma-Scrawl-4-BRK
    family: Ænigma Scrawl 4 BRK
    style: Normal
    stretch: Normal
    weight: 400
    glyphs: /usr/share/fonts/truetype/aenigma/aescrawl.ttf

 

Sin embargo, pese a que convert muestra toda esa información el nombre de la tipografía que vamos a usar a la hora de generar un texto con ImageMagick es el que sucede a "Font:". Así pues, si lo que queremos es saber el nombre con el que podremos invocar a las tipografías desde convert para añadir textos en nuestras imágenes o generar imágenes con texto, podremos listar únicamente esas líneas. Y aquí es donde llamamos a nuestro amigo grep:

convert -list font | grep Font

Font: Zakenstein-Rotalic
Font: Zekton
Font: Zekton-Bold
Font: Zekton-Bold-Italic
Font: Zekton-Dots
Font: Zekton-Italic
Font: Zelda-DX-TT-BRK
Font: Zenith-BRK
Font: Zephyrean-BRK
Font: Zephyrean-Gust-BRK
Font: Zero-Threes
Font: Zero-Twos
Font: Zero-Velocity-BRK
Font: ZeroHour
Font: Zirconia-BRK
Font: Zirconia-Cubic-BRK
Font: Zodillinstrisstirust
Font: Zoetrope-BRK
Font: Zoidal-BRK
Font: Zrnic
Font: Zurklez-Outline-BRK
Font: Zurklez-Solid-BRK
Font: Æ-Systematic-TT-BRK
Font: Ænigma-Scrawl-4-BRK


Otra fórmula sería extraer la columna donde están las cadenas de texto que contienen los nombres de las tipografías, el comando cut ayuda mucho en esta tarea:

convert -list font | grep Font | cut -d " " -f 4

Con estos parámetros le decimos a cut, que es un comando que "corta" cadenas, que el separador es un espacio en blanco con -d " ".

Del mismo modo, le podríamos indicar que el separador de columnas es cualqueir otro caracter o cadena de caracteres. El parámetro -f lo que indica es el número de la columna que ha de mostar, en este caso, la cuarta. Veamos:

Zekton
Zekton-Bold
Zekton-Bold-Italic
Zekton-Dots
Zekton-Italic
Zelda-DX-TT-BRK
Zenith-BRK Zephyrean-BRK
Zephyrean-Gust-BRK
Zero-Threes Zero-Twos
Zero-Velocity-BRK
ZeroHour Zirconia-BRK
Zirconia-Cubic-BRK
Zodillinstrisstirust
Zoetrope-BRK
Zoidal-BRK
Zrnic
Zurklez-Outline-BRK
Zurklez-Solid-BRK
Æ-Systematic-TT-BRK
Ænigma-Scrawl-4-BRK

Y ahora que ya tenemos el listado limpio, únicamente tenemos que elegir una cadena al azar. Lo podemos hacer con shuf:
convert -list font | grep Font | cut -d " " -f 4 | shuf -n 1
Intersect-O-BRK

Y si lo probamos muchas veces, veremos que el resultado es aleatorio, por lo que cada vez que ejecutemos esa instrucción será distinta:

tipografiaaleatoria.png

 

Y dentro de un script, el uso sería igual:

#!/bin/bash

tipografia=$(convert -list font | grep Font | cut -d " " -f 4 | shuf -n 1)

echo "La tipografía seleccionada de forma aleatoria ha salido: "$tipografia

Veamos si así funciona:

tipografiaaleatoria.png

 

Como vemos, cada vez que ejecutamos el script nos muestra una tipografía distinta.

Y ahora, vamos a usarlo con ImageMagick para generar una imagen con una tipografía aleatoria:

#!/bin/bash

tipografia=$(convert -list font | grep Font | cut -d " " -f 4 | shuf -n 1)

convert -pointsize 100 -font $tipografia label:"Disfruten del\nSoftware Libre" disfruten.png

disfruten.png

 

Y vamos a hacer un for para comprobar que realmente genera imágenes con distintas tipografías:

#!/bin/bash

for i in $(seq 1 3)
do
    tipografia=$(convert -list font | grep Font | cut -d " " -f 4 | shuf -n 1)
    convert -pointsize 100 -font $tipografia label:"Disfruten del\nSoftware Libre" disfruten$i.png
done


disfruten1.pngdisfruten3.pngdisfruten2.png

Vista la forma básica de generar textos con tipografías aleatorias, veremos también cómo hacer una selección previa de las tipografías para usar aquellas tipografías que se ajusten a nuestras necesidades.

Estoy haciendo una serie de tutoriales de GIMP 2.10 y quería mostrar cómo van cambiando las imágenes al cambiar los valores de los deslizadores de las distintas herramientas que forman GIMP.

Una opción es capturar la pantalla con recordMyDesktop o ffmpeg y colgarlo tal cual. El problema de esto es que el entorno de GIMP ocupa un espacio que hace que la imagen se vea pequeña. Así que prefiero hacer un efecto PiP (Picture in Picture). Es decir, superponer una imagen, en este caso, la caja de la herramienta sobre otra imagen más grande, en este caso, la imagen que va cambiando según los valores dados en la caja de la herramienta.

Podría capturar la pantalla y con un editor de vídeo, por ejemplo, Kdenlive, duplicar la pista y hacer dos "crops": uno con la imagen y otro con la herramienta, superponer ambas y montar el vídeo. Aparte de que el proceso de edición es farragoso, debería también hacer muchas veces clic con el ratón. Demasiado trabajo... seguro que ImageMagick me permite hacer el mismo resultado con menos esfuerzo. Veamos cómo hacerlo:

1.- Para el primer ejemplo, he cogido la primera herramienta del menú de Color de GIMP. Y me aparece que los deslizadores van del -100 al 100. Así que, en lugar de hacer 201 clic con el ratón, voy a hacer un bucle con una secuencia del 0 al 200.

2.- En cada iteración voy a capturar la pantalla completa con import y hacer dos recortes con crop, por un lado, la imagen que va cambiando y por otro, la herramienta de turno, en este caso, "Balance de color".

3.- Como quiero que el vídeo esté en formato HD, paso la imagen a un tamaño de 1920x1080 píxeles.

4.- Superpongo las imágenes con composite y hago clic para aumentar el valor.

5.- Le digo a ffmpeg que haga un vídeo con todos los fotogramas

6.- Y borro las imágenes sobrantes

Ya he escrito previamente sobre todas las instrucciones de este script a excepción de xdotool, que es un comando para simular el manejo del ratón a través de línea de comandos. Permite cliquear con los distintos botones, mover la ruleta, mover el cursor, hacer doble clic... En este caso, como únicamente quiero que haga un clic con el botón izquierdo, usaré:

xdotool click 1

 

Así es como queda el script:

#!/bin/bash

for i in $(seq 0 200)
do
    import -w root pantallazo.png
    convert pantallazo.png -crop 1308x735+172+214 lienzo$1$i.png
    convert pantallazo.png -crop 412x501+1497+242 -background Transparent -gravity Center -extent 600x600  deslizador$1$i.png

    convert lienzo$1$i.png -resize 1920x1080 base.png
    composite -gravity SouthEast  deslizador$1$i.png base.png png:-
xdotool click 1
done | ffmpeg -f image2pipe -i - videos/$1.mp4

rm lienzo*
rm deslizador*

Y así queda el resultado:

Podemos descargar en nuestro ordenador todos los tuits de un usuario de Twitter pinchando uno a uno, dándole botón derecho y guardando la página... o haciendo un pequeño script. 

Veamos paso a paso cómo hacerlo:

Acotar la búsqueda

Vamos a usar la cuenta de @LinuxCenterEs como ejemplo, así que vamos a mirar cuándo se unió a twitter, a qué fecha estamos y usaremos esos dos datos para delimitar el rango temporal desde donde hay que descargar.

Para saber la fecha actual, usaremos date.

Para saber la fecha en la que se unió un usuario a Twitter, tenemos que mirar en el código fuente. Para saber qué cadena buscamos, vamos a mirar primero la fecha en el perfil del usuario:

fechatwitter.png

 

Después buscamos esa cadena en el código fuente y miramos a qué clase o div pertenece:

clasetwitter.png

 

Y comprobamos si esa clase se utiliza únicamente para ese dato:

unacierto.png

Ya tenemos la pista con la que extraer la cadena de la fecha en la que se unió el usuario a Twitter.

Ahora tenemos que descargar la página, buscar la línea y extraer únicamente la cadena:

#!/bin/bash

wget https://twitter.com/$1 -O $1.html

lineafecha=$(cat $i.html | grep "ProfileHeaderCard-joinDateText js-tooltip u-dir")

echo $lineafecha

 

Voy a comprobar si funciona hasta aquí:

 

Por ahora parece que vamos bien. Ahora vamos a limpiar la cadena.

Ojo, tenemos que limpiar acorde con el idioma de nuestro sistema. Si, por ejemplo, tuviésemos el sistema en inglés, la cadena es distinta:

 

Veamos cómo llevamos el script hasta ahora:

#!/bin/bash

wget https://twitter.com/$1 -O $1.html

lineafecha=$(cat $i.html | grep "ProfileHeaderCard-joinDateText js-tooltip u-dir")

mescomienzo=$(echo $lineafecha | cut -d " " -f 13)
anocomienzo=$(echo $lineafecha | cut -d " " -f 15 | cut -d "<" -f 1)

case $mescomienzo in
enero)
    mescomienzo="01"
;;
febrero)
    mescomienzo="02"
;;
marzo)
    mescomienzo="03"
;;
abril)
    mescomienzo="04"
;;
mayo)
    mescomienzo="05"
;;
junio)
    mescomienzo="06"
;;
julio)
    mescomienzo="07"
;;
agosto)
    mescomienzo="08"
;;
septiembre)
    mescomienzo="09"
;;
octubre)
    mescomienzo="10"
;;
noviembre)
    mescomienzo="11"
;;
diciembre)
    mescomienzo="12"
;;
esac


mesfinal=$(date +%m)
anofinal=$(date +%Y)

echo "Las fechas a buscar son desde el "$mescomienzo" de "$anocomienzo" hasta el "$mesfinal" de "$anofinal

 Y veamos si funciona bien:

 

Pues parece que vamos por buen camino. Así que seguimos:

Ahora que ya sabemos las fechas que hemos de recorrer, vamos a ver cómo explotar este dato, tal como adelanté en un hilo de twitter: https://twitter.com/hacemoswebserie/status/1040037466802151426

Antes de seguir, comentaré que la cadena para hacer una búsqueda de los tuits que un determinado usuario de Twitter ha publicado entre dos fechas es:

"https://twitter.com/search?q=From%3A"$1"%20since%3A"$anocomienzo"-"$mescomienzo"-"$diacomienzo"%20until%3A"$anofinal"-"$mesfinal"-"$diafinal"&src=typd"

Y siempre es así. Simplemente cambiando las variables. Pero lo mejor de todo, es que todas las redes sociales siguen patrones similares, por lo que este tutorial es extrapolable a cualquier otra red social o cualquier otra búsqueda dentro de Twitter.

Y una advertencia, a veces si hacemos muchas descargas desde una misma IP o desde un mismo navegador, puede que nos bloquee ese servidor las descargas y no sirva nuestro script. Varias soluciones para esto:

  • Usar Tor para usar distintas IPs.
  • Lanzar varios scripts desde distintos ordenadores con distintas IPs (mejor si usamos servidores desde distintos puntos del planeta).
  • Ir cambiando de "user agent", es decir, cambiar la cabecera de wget para que se haga pasar por otro navegador. Tenemos un enorme listado de cabeceras en la página http://www.useragentstring.com/

Pero si vamos a hacer un uso moderado, como en este ejemplo en el que descargarnos los tuits de un único usuario, no debería darnos más problema que no nos deja descargar con wget si no le indicamos un "user agent" distinto.

Así que le indicaremos a wget que, por ejemplo, usamos Firefox con Windows. Lo haremos con: wget --user-agent="Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.2.3) Gecko/20100401 Lightningquail/3.6.3"

Y nos quedaría un script así:

#!/bin/bash

lineafecha=$(cat $i.html | grep "ProfileHeaderCard-joinDateText js-tooltip u-dir")

mescomienzo=$(echo $lineafecha | cut -d " " -f 13)
anocomienzo=$(echo $lineafecha | cut -d " " -f 15 | cut -d "<" -f 1)

case $mescomienzo in
enero)
    mescomienzo="01"
;;
febrero)
    mescomienzo="02"
;;
marzo)
    mescomienzo="03"
;;
abril)
    mescomienzo="04"
;;
mayo)
    mescomienzo="05"
;;
junio)
    mescomienzo="06"
;;
julio)
    mescomienzo="07"
;;
agosto)
    mescomienzo="08"
;;
septiembre)
    mescomienzo="09"
;;
octubre)
    mescomienzo="10"
;;
noviembre)
    mescomienzo="11"
;;
diciembre)
    mescomienzo="12"
;;
esac


mesfinal=$(date +%m)
anofinal=$(date +%Y)


for a in $(seq $anocomienzo $anofinal)
do
    for m in $(seq 1 12)
    do
            if [ $m -lt 10 ]
            then
                m="0"$m
            fi
            cadena="https://twitter.com/search?q=From%3A"$1"%20since%3A"$a"-"$m"-01%20until%3A"$a"-"$m"-31&src=typd"
            wget --user-agent="Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.2.3) Gecko/20100401 Lightningquail/3.6.3" $cadena -O "tuits-"$m"-"$a".html"

    done
done

Sobre esta base, podemos seguir evolucionando, como definir que el primer año sólo descargue a partir del mes de comienzo, que el último año sólo descargue hasta el mes de final, que descargue los tuits día a día... Eso a gusto de cada uno.

En cuanto a usos, una vez descargados todos los tuits, podemos analizar las candenas con múltiples fines, desde hacer análisis de mercados, comprobar el número de adjetivos, sustantivos, pronombres... que utiliza ese usuario, o, por ejemplo, saber cuántas veces nos cita ese usuario:

Veamos cómo se porta LinuxCenterEs conmigo:

#!/bin/bash

let contador=0

for i in $(ls *.html)
do
    let nominaciones=$(cat $i | grep -c hacemoswebserie)
    let contador=$contador+$nominaciones
    let nominaciones=0
done

echo "Te han citado "$contador" veces."

 

Veamos si funciona:

nominaciones.png

 

Y como funciona todo hasta aquí, aquí dejo el artículo. Ahora es tarea de cada usuario el adaptar este artículo a sus intereses. Las bases están sentadas... que la evolución haga el resto.

 

Jueves, 13 Septiembre 2018 17:08

Trabajar con fechas en Bash

Para trabajar con fechas y con horas en un script, o en la consola, tenemos el comando date. Veamos su uso y algunos de sus parámetros más usuales.

Si únicamente escribimos date, nos devuelve el día de la semana indicado con tres caracteres; el mes, indicado de nuevo con tres caracteres; la hora completa con hora, minutos y segundos; el huso horario de nuestro ordenador y el año actual.

Parámetros usuales:

date +%H -> indica la hora (sin minutos) actual

date +%M -> indica los minutos actuales

date +%H:%M -> indica la hora y minutos actuales

date +%d -> indica qué día del mes es hoy
date +%m -> indica el mes actual en número

date +%B -> indica el mes actual en letras, con la palabra completa

date +%Y -> indica el año actual

Ejemplo:

echo "Hoy es el "$(date +%D)" de "$(date +%B)" de "$(date +%y)

Truco para usar date

Puede que te preguntes si te tienes que aprender todas esas opciones para hacer un uso eficaz de date. No. No hace falta. GNU/Linux es un sistema que permite optimizar todos los recursos... incluída la memoria de los usuarios. Con un sencillo script, podemos indicarle a un array que incluya las letras mayúsculas, a otro que incluya las minúsculas, concatene ambos arrays y lo recorra devolviendo el restultado de pasarle esos parámetros a date.

Hecho esto, lo ejecutamos y vemos qué parámetros son los que más nos interesan... incluso vemos qué letras no son parámetros de date.

Aquí dejo el script:

#!/bin/bash

minusculas=({a..z})
mayusculas=({A..Z})
letras=($(echo ${minusculas[*]}) $(echo ${mayusculas[*]}))

for i in $(seq 0 ${#letras[*]})
do
    echo "date +"${letras[$i]}"%: "$(date +%${letras[$i]})
done

Miércoles, 12 Septiembre 2018 20:31

Generar números aleatoriamente con shuf

Ya hemos visto que, dado que %$valor lo que hace es calcular el resto de la división entre la cifra que precede a % (dividendo) y la cifra que sucede a % (divisor), $RANDOM%limitesuperior no vale para generar números aleatorios de forma fideligna (a no ser que seamos trileros, pero en este caso no buscamos una verdadera aleatoriedad).

También hemos visto que shuf sí que sirve para crear órdenes aleatorios. Y ahora vamos a ver cómo usar shuf para generar números aleatorios.

Lanzamiento a cara o cruz de una moneda (aleatoriedad entre dos valores)

Veamos cómo usar shuf en el primer ejemplo que usé en contra de $RANDOM: una aleatoriedad dos valores. Pero antes de ello, vuelvo a remarcar que shuf no genera nada, sino que hace un orden aleatorio de una lista. Así que primero hay que generar una lista y luego ordenar aleatoriamente con shuf.

¿Qué formas podemos generar una lista?

Veamos varias formas de hacerlo:

En un fichero auxiliar:

#/bin/bash

let comienzo=0
let final=1

for i in $(seq $comienzo $final)
do
    echo $i >> numeros.txt
done

Y ahora podemos ejecutarlo y luego ordenar con shuf. Veamos a ver si la aleatoriedad es tal:

 

En este pantallazo vemos que de 12 tiradas, han salido siete veces 0 y cinco veces 1. Está dentro de la normalidad. Pero vamos a ver qué ocurre si tiramos mil veces la moneda:

#/bin/bash

let ceros=0
let unos=0

for i in $(seq 1 1000)
do
    let moneda=$(shuf -n1 numeros.txt)
    if [ $moneda -eq 0 ]
    then
        let ceros++
    else
        let unos++
    fi
done

echo "El número de ceros que ha salido es: "$ceros
echo "El número de unos que ha salido es: "$unos

Y lo comprobamos (vuelvo a poner pantallazo para que se vea que no hay trampa ni cartón):

comprobacionconfichero.png

 

¡Incluso me ha llegado a dar un empate de 500 a 500!

Visto que shuf es más válido en este caso, vamos a ver cómo generar una lista aleatoria con shuf. Compruebo en el mismo script para evitar hacer un artículo excesivamente largo:

#/bin/bash

let ceros=0
let unos=0

for i in $(seq 1 1000)
do
    numeros=$(shuf -i 0-1)    
    if [[ ${numeros:0:1} == "0" ]]
    then
        let ceros++
    else
        let unos++
    fi
done

echo "El número de ceros que ha salido es: "$ceros
echo "El número de unos que ha salido es: "$unos

listaconshuf.png

 

Funciona... y de nuevo hemos tenido un empate a 500 en una tirada.

Pero ahora te puedes preguntar, por qué si existe el parámetro -i en shuf para generar una lista con orden aleatorio y el parámetro -n para extraer un número determinado de elementos, ¿por qué no lo usas en la misma línea?

No te falta razón para pensarlo, pero quería mostrar distintas formas de lanzar la moneda. Y hacer un artículo evolutivo que acabase con la mejor opción:

#/bin/bash

let ceros=0
let unos=0

for i in $(seq 1 1000)
do
    numeros=$(shuf -i 0-1 -n 1)    
    if [[ $numeros == "0" ]]
    then
        let ceros++
    else
        let unos++
    fi
done

echo "El número de ceros que ha salido es: "$ceros
echo "El número de unos que ha salido es: "$unos

listaconshufin.png

Y vuelve a funcionar... incluso me ha dado otro empate a 500.

¿Y si en lugar de tirar a cara o cruz hacemos un rango mayor, por ejemplo de 0 a 1000?

Simplemente le cambiamos el rango en -i. Y si además, para comprobar si funciona, vamos a aumentar el número de tiradas.

#/bin/bash

let ceros=0
let quinientos=0
let miles=0

for i in $(seq 1 10000)
do
    numeros=$(shuf -i 0-1000 -n 1)    
    if [[ $numeros == "0" ]]
    then
        let ceros++
    elif [[ $numeros == "500" ]]
    then
        let quinientos++
    elif [[ $numeros == "1000" ]]
    then
        let miles++
    fi
done

echo "El número de ceros que ha salido es: "$ceros
echo "El número de quinientos que ha salido es: "$quinientos
echo "El número de miles que ha salido es: "$miles

Y al probarlo, da unos resultados tales como:

 

 

delunoalmil.png

 

Que son unos resultados que son totalmente coherentes dentro de lo que es la aleatoriedad por lo que podemos decir que la mejor forma para generar un número aleatorio en Bash es

shuf -i $limiteinferior-$limitesuperior -n 1

Miércoles, 12 Septiembre 2018 00:02

Aleatoriedad con shuf

En tres artículos he estado argumentando en contra del uso de $RANDOM para generar números aleatorios:

El mito de $((RANDOM%$limitesuperior))
Más sobre la "aleatoriedad" de $RANDOM
Dados cargados en $RANDOM

Pero es poco honesto criticar algo sin aportar una solución, así que aquí voy a explicar el uso de shuf y en otro artículo explicaré varias formas de usar shuf para generar números aleatorios.

El uso de shuf

shuf se puede usar para ordenar aleatoriamente un fichero de texto:

shuf fichero.txt

shuf.png

Como vemos al usar cat, las palabras de fichero.txt tenían un orden que, al usar shuf, han cambiado de orden.

También shuf permite seleccionar X elementos de una lista. Ya lo hemos usado otras veces, como al elegir aleatoriamente una tipografía o un color con ImageMagick. Pero veamos con el ejemplo anterior:

shuf -n2 fichero

Con el parámetro -n$numerodelineas muestra el número de líneas incado como valor a -n.

Otra forma de usar shuf es recibiendo una lista desde la salida de otro fichero.

Veamos un ejemplo creando una serie de ficheros en un directorio y luego seleccionando uno al azar recogiendo con shuf la salida de ls.

 

Otro parámetro muy interesante es -o para especificar un fichero donde guardar la salida de shuf. Evolucionemos la instrucción anterior:

ls | shuf -o ordenaleatorio.txt

Sábado, 08 Septiembre 2018 22:27

Hacer un gif a partir de un vídeo de YouTube

¿Os han pedido alguna vez que tuiteeis algún gif de alguna película? A mi, sí. Hace unos minutos. Así que ya que voy a hacer un gif de una de mis películas favoritas, os cuento cómo hacerlo. Pero no es necesario que os pidan un gif de una película, si queréis hacer un gif a partir de un vídeo de YouTube, podéis seguir paso a paso este artículo. En caso de que tengáis el vídeo en vuestro ordenador, podéis obviar la parte de la descarga del vídeo.

Descargar el vídeo de YouTube

Para descargar un vídeo de YouTube, o casi de cualquier plataforma de vídeo, incluídas muchas plataformas de vídeos para adultos, tenemos un comando súper eficiente para ello: youtube-dl. Su uso más básico es para descargar un vídeo (si quieren que escriba un artículo explicando cómo descargar sólo audio o una lista de vídeos, escríbanlo en los comentarios). Y para descargar un vídeo no necesitamos ni parámetros ni nada más que el comando y la url del vídeo. Como yo quiero tuitear sobre Machete (como digo, me han pedido un gif de una de mis películas favoritas, así que elijo esta escena de Machete):

https://www.youtube.com/watch?v=DTyeEB-ra7w

Y lo descargo con:

youtube-dl https://www.youtube.com/watch?v=DTyeEB-ra7w

Extraer los fotogramas de la parte del vídeo que interesa

Como he visto el vídeo de YouTube y sé que la parte de la que quiero extraer los fotogramas va de 00:14 a 00:21 uso el comando:

ffmpeg -i Machete\ improvises-DTyeEB-ra7w.mp4 -ss 00:14 -t 8 machete%04d.jpg

Escribir un texto sobre los fotogramas

Voy a escribir dos frases: "Machete no manda mensajes" y "Machete improvisa". Para ver sobre qué fotogramas escribo cada una de las frases, voy a mirar dónde está el cambio de plano:

cambiodeplano.jpg

 

Hasta el fotograma machete0056.jpg voy a poner "Machete no manda mensajes" y en el resto, hasta el 200, "Machete improvisa":

#!/bin/bash

for i in $(seq 1 200)
do
    if [ $i -lt 10 ]
    then
        sufijo=000$i.jpg
    elif [ $i -lt 100 ]
    then
        sufijo=00$i.jpg
    else
        sufijo=0$i.jpg
    fi

    if [ $i -lt 56 ]
    then
        convert machete$sufijo -gravity South -font Luxi-Sans-Bold -pointsize 50 -fill White -stroke Black -strokewidth 3 -annotate +0+0 "MACHETE NO MANDA MENSAJES" fotograma$sufijo
    else
         convert machete$sufijo -gravity South -font Luxi-Sans-Bold -pointsize 70 -fill White -stroke Black -strokewidth 3 -annotate +0+0 "MACHETE IMPROVISA" fotograma$sufijo
    fi
done

Optimizando la animación

En este caso, la mayoría de los fotogramas son iguales o muy parecidos, así que voy a borrar unos cuantos. Al contrario que con ffmpeg, a la hora de hacer imágenes animadas con ImageMagick la numeración puede contener saltos.

Y además, tenemos la posibilidad de optimizar las imágenes para que el fichero resultante pese menos con -layers Optimize, que podemos usarlo así:

convert fotograma0* -delay 5 -loop 0 -layers Optimize macheteimprovisa.gif

Podéis ver el resltado en Twitter:
https://twitter.com/hacemoswebserie/status/1038551976131350528

 

 

Ya hemos visto cómo unir imágenes con -delay para crear un gif animado. Pero -delay, que es muy sencillo de usar, no permite definir cuántas veces queremos que se repita el bucle ni la velocidad a la que queremos que se muestren las imágenes que forman la animación.

Para estas dos funcionalidades tenemos:

-loop que permite definir el número de veces que queremos que se repita una determinada animación. Le indicamos el número de veces que queremos que se repita. Y si queremos que se repita infinitas veces, se lo indicamos con 0.

-delay que establece la velocidad a la que se mostararán las imágenes en centésimas de segundo. Es decir, si queremos que entre imagen e imagen pase un segundo, le indicaremos 100.

Así:
convert -delay 10 -loop 0 param* param.gif

Si quieren ver diversas fórmulas para crear imágenes que van mutando y luego unirlas en ficheros gif, pueden leer este hilo de Twitter:

https://twitter.com/hacemoswebserie/status/1037884393430429699

¡Atención! Este sitio usa cookies y tecnologías similares.

Si no cambia la configuración de su navegador, usted acepta su uso. Saber más

Acepto

Vea nuestra política de cookies y enlaces de interés aquí