Linux Center Valencia - Elementos filtrados por fecha: Agosto 2018
Viernes, 31 Agosto 2018 22:26

Capturar pantallazos con import

Import es una herramienta de la suite ImageMagick que permite capturar imágenes de la pantalla del ordenador. Podemos caputrar la pantalla completa, únicamente una ventana, una porción de la ventana... veamos cómo hacerlo:

La sintaxis básica del comando sería:

import pantallazo.png

Al escribir esto, se nos pone el cursor en forma de cruz. Con este cursor, podemos hacer dos cosas:

Pinchar sobre una ventana y capturará toda la ventana:

pantallazo.png

Seleccionar una zona con el ratón y se capturará esa zona:

 

Otra opción que nos permite trabajar sin el ratón es capturar toda la pantalla con import -w nombredelaventana (para la pantalla completa, usaremos root) y con la pantalla capturada, podemos escalarla, seleccionar una zona...

import -w root -resize 500x pantallacompleta.png

pantallacompleta.png

 

import -w root -crop 500x300+0+0 pantallarecortada.png

pantallarecortada-0.png

 

También podemos usar gravity:

import -w root -gravity Center -crop 500x300+0+0 pantallarecortadacentrada.png

pantallarecortadacentrada.png

 

Para preparar bien la captura, por ejemplo, si queremos que no aparezca la pantalla de la terminal o poner en primer plano la pantalla que queremos capturar, podemos decirle a import que haga una pausa desde que le indicamos que capture hasta que haga la captura. Se lo indicamos con -pause $numero de segundos.

import -pause 2 -w root pantallazo.png

Y si queremos hacer una gran cantidad de capturas con pausas, por ejemplo, para mostrar los distintos menús de una aplicación, podemos hacer un script:

#!/bin/bash
for i in $(seq 1 100)
do
    import -pause 2 -w root pantallazo$i.jpg
done

 

 

Publicado en Multimedia
Jueves, 30 Agosto 2018 23:01

Crear lienzos con textos en ImageMagick

Vamos a ver cómo crear lienzos con textos en ImageMagick. Es decir, crear una imagen de la nada con un fondo y letras. Para escribir sobre una imagen existente está el parámetro -annotate, pero eso es materia de otro artículo.

Para crear estos lienzos con textos veremos los siguientes parámetros de convert:

-size: determina el tamaño de la imagen

-font: especifica la tipografía a utilizar

-pointsize: permite especificar el tamaño de la tipografía

label: (no lleva guión delante) indica la etiqueta que se escribirá en el lienzo, el texto a escribir

-gravity: localiza el punto de referencia sobre el que se posicionará el texto

-background: establece el color de fondo del lienzo

-fill: especifica el color principal con el que trabajaremos, en caso de los textos, el color de las letras

-interword-spacing: separación entre las palabras

-kerning: separación entre las letras

-interline-spacing: separación entre líneas

Para ver cómo funcionan cada uno de estos parámetros, veremos una serie de ejemplos que lo ilustren:

Texto por defecto en negro sobre blanco:

convert label:"Todo está en los libros" negrosobreblanco.jpg

 

negrosobreblanco.jpg

 

Si únicamente le indicamos el parámetro label, utiliza la tipografía y el tamaño por defecto, dependiendo de la versión y de las tipografías instaladas en el equipo.

Texto en negro sobre lienzo blanco de un tamaño específico

convert -size 300x100 label:"Todo está en los libros" negrosobreblanco2.jpg

negrosobreblanco2.jpg

Al indicarle el tamaño del lienzo con -size, convert ajustará el tamaño del texto para que ocupe todo el lienzo. Y, como podemos ver en la imagen, el punto de gravedad por defecto es NorthWest. Podemos especificar únicamente la anchura con $anchurax o únicamente la altura con x$altura.

Texto centrado negro sobre lienzo blanco de un tamaño específico

convert -size 300x100 -gravity Center label:"Todo está en los libros" negrosobreblanco3.jpg

negrosobreblanco3.jpg

 

Podemos especificar que el texto esté centrado con el parámetro -gravity Center.

Texto centrado negro sobre lienzo azul de un tamaño específico

convert -size 300x100 -background Blue -gravity Center label:"Linux Center" linuxcenter.jpg

Por defecto, convert escribe el texto en negro sobre fondo blanco, pero podemos cambiar el color del fondo con -background.

Texto centrado blanco sobre lienzo azul de un tamaño específico

convert -size 300x100 -background Blue -fill White -gravity Center label:"Linux Center" linuxcenter2.jpg

 

Al igual que podemos cambiar el color del lienzo, también podemos cambiar el color del texto. Lo especificaremos con -fill (que indica el color con el que trabajaremos en las siguientes operaciones, algo así como "color de frente", no sólo a la hora de escribir un texto, sino con muchos más modificadores).

Texto centrado blanco de un tamaño específico sobre lienzo azul de un tamaño específico

convert -size 300x100 -background Blue -fill White -gravity Center -pointsize 20 label:"Linux Center" linuxcenter3.jpg

linuxcenter3.jpg

El tamaño del texto lo indicamos con -pointsize

Texto centrado blanco de un tamaño específico sobre lienzo azul

convert -background Blue -fill White -gravity Center -pointsize 20 label:"Linux Center" linuxcenter4.jpg

linuxcenter4.jpg

Antes hemos visto que si indicamos el tamaño del lienzo pero no el tamaño de las letras, convert ajusta el tamaño de las letras para que se ajusten al tamaño del lienzo.

Del mismo modo, si indicamos el tamaño de las letras pero no indicamos el tamaño del lienzo, convert ajusta el tamaño del lienzo al texto.

 

Texto centrado blanco de una tipografía determinada con un tamaño específico sobre lienzo azul

convert -background Blue -fill White -gravity Center -font Unispace -pointsize 20 label:"Linux Center" linuxcenter5.jpg

linuxcenter4.jpg

Seleccionamos la tipografía con -font. Podemos ver todas las tipografías con convert -list font

Texto centrado blanco de una tipografía determinada con un tamaño y una separación entre letras específica sobre lienzo azul

convert -background Blue -fill White -gravity Center -font Unispace -pointsize 20 -kerning 5 label:"Linux Center" linuxcenter6.jpg

linuxcenter6.jpg

Con -kerning especificamos la separación entre las letras. Como vemos, si no especificamos el tamaño del lienzo, convert lo ajustará al texto con la separación que indiquemos.

Texto en dos líneas

convert -background Blue -fill White -gravity Center -font Unispace -pointsize 20 -kerning 5 label:"Linux \nCenter" linuxcenter7.jpg

linuxcenter7.jpg

Para separar las líneas, indicaremos el salto de línea con \n.

Texto en dos líneas indicando el espacio entre líneas

convert -background Blue -fill White -gravity Center -font Unispace -pointsize 20 -interline-spacing 10 -kerning 5 label:"Linux \nCenter" linuxcenter8.jpg

linuxcenter8.jpg

El tamaño entre líneas se especifica en ImageMagick con -interline-spacing

Indicar la separación entre palabras

convert -background Blue -fill White -gravity Center -font Unispace -pointsize 20 -interword-spacing 20 -kerning 5 label:"Linux Center" linuxcenter9.jpg

 

linuxcenter9.jpg

Podemos indicar, además de la separación entre las letras y entre las líneas, la separación entre las palabras. Lo indicamos con -interword-spacing

 

Básicamente estos son los parámetros para generar lienzos con texto en ImageMagick. Y me despido con un comando que aglutina todos estos parámetros:

convert -size 300x200 -background White -fill Blue -gravity Center -font FreeMono-Negrita -pointsize 30 -interword-spacing 10 -kerning 5 -interline-spacing 10 label:"Deseo que\nhaya sido\nde su interés" -bordercolor Black -border 10x10 despedida.jpg

Publicado en Multimedia

Tenemos un vídeo, al que llamaremos video.mp4

Tenemos una pista de audio, a la que llamaremos audio.mp3

Tenemos una necesidad, que es unir la pista de audio al vídeo.

Tenemos un programa en nuestra shell, que es ffmpeg.

Combinamos todo:

ffmpeg -i video.mp4 -i audio.mp3 -c:v copy -c:a copy videoconaudio.mp4

Y ahora que tenemos la pista de audio y la de vídeo unidas, vamos a ver qué hemos hecho:

ffmpeg -> nombre del comando

-i video.mp4 -> definimos una entrada

-i audio.mp3 -> definimos otra entrada

-c:v copy -> definimos que no queremos cambiar el códec de vídeo (copia el que tiene la pista de vídeo)

-c:a copy -> definimos que no queremos cambiar el códec de audio (copia el que tiene la pista de audio)

videoconaudio.mp4 -> nombre del fichero que se generará con la unión de la pista de vídeo y la pista de audio.

Publicado en Multimedia
Miércoles, 29 Agosto 2018 22:16

Función para numerar fotogramas

Ahora que sabemos editar un vídeo a partir de una secuencia de fotogramas con ffmpeg nos encontramos con que para poder hacerlo, los fotogramas han de estar numerados correlativamente y todos con el mismo número de dígitos en el numeral para que los ordene bien en el vídeo, lo cual es sencillo, pero si lo automatizamos, mejor.

Aquí os dejo la función que utilizo para ello:

function devuelvefotograma()
{

# Función que recibe el numeral del último fotograma creado y devuelve el fotograma a utilizar como imagen destino por convert


    esentero='^[0-9]+$'
    numerofotograma=$1
    
    if [ -z $numerofotograma ] || ! [[ $numerofotograma =~ $esentero ]]
    then
        let numerofotograma=1
    fi
    

    if [ $numerofotograma -lt 10 ]
    then
        fotograma="fotograma000"$numerofotograma".png"
    
    elif [ $numerofotograma -ge 10 ] && [ $numerofotograma -lt 100 ]
    then
        fotograma="fotograma00"$numerofotograma".png"
    elif [ $numerofotograma -ge 100 ] && [ $numerofotograma -lt 1000 ]
    then
        fotograma="fotograma0"$numerofotograma".png"
    else
        fotograma="fotograma"$numerofotograma".png"
    fi

    echo $fotograma;
}

 

Explicación de la función

 

Primero defino la función y le llamo devuelvefotograma, ya que me gusta que el nombre de una función sea descriptivo, así que suelo usar un imperativo que indique lo que quiero que haga.
Una descripción de qué va a hacer la función. 
Y comienzo la función diciéndole que $numerofotograma (también un nombre que deje claro qué va a almacenar esa variable) tome el valor de $1, es decir, del primer parámetro que le pasamos a la función. Y no es que no me guste usar el nombre de la variable $1, sino que $1 es genérico para todas las funciones y $numerofotograma es más sencillo de entender (sí, hay que teclear un poco más, pero a la hora de mantener un script es mejor si el nombre de las variables indican qué contienen. Y si tienes configurado en tu editor de textos que al pulsar tabulador complete los nombres de las funciones, tampoco tienes que teclear mucho más).
Le indico también que la variable $esentero sea una expresión regular que diga que desde el comienzo hasta el final sean números ('^[0-9]+$').

Compruebo si no tiene contenido en la variable ([ -z $numerofotograma ]) o (||) no es numérico (! [[ $numerofotograma =~ $esentero ]]) y si no tiene nada la variable o no es numérica, le soy el valor 1. Ya sé que puede sobreescribir fotogramas al hacerlo así, pero prefiero darle un valor a la variable que me de error la función. A gustos.

Pregunto si $numerofotograma es menor que 10 con [ $numerofotograma -lt 10 ], es decir, si únicamente tiene un carácter. Si es así, le añado tres ceros. Por ejemplo, si el número del fotograma es 1, le digo que sea 0001.

Si es igual o mayor que 10 ([ $numerofotograma -ge 10 ]) y además (&&), es menor que cien ([ $numerofotograma -lt 100 ]) es que tiene dos carácteres, así que le añado dos ceros. Si tiene tres carácteres es que va de 100 a 999, así que le digo que si es igual o mayor que cien y menor que mil, que añada un 0.

Y si es mayor que 1000 es que tiene 4 dígitos o más. Y no añado ningún cero. Alguien podría decir que qué pasa si hay más de 9.999 fotogramas. Sencillamente, que no uso esta función, ya que usaría la opción de codificar el vídeo al vuelo. Esta función la uso para generar y ver los fotogramas antes de renderizar un vídeo. Si un vídeo tiene más de 9.999 fotogramas puede ocupar unos 70 Gb de espacio en disco. Y no voy a visualizar individualmente tantos fotogramas.
La opción de visualizar fotograma a fotograma es para secuencias cortas en las que hay detalles importantes o una muestra para ver cómo quedan los fotogramas antes de hacer el vídeo.

Por último, devuelvo $fotograma.

Variables e invocación de la función

Podemos definir la variable $numerofotograma o no. Si no la inciamos, la función la inicializa a 1. Si la queremos inicializar, por hacer un script más elegante, lo podemos hacer con:

let numerofotograma=1

Invocamos a la función pasándole el número de fotograma como parámetro y nada más saber el fotograma a utilizar, le decimos que le sume 1. Podemos hacerlo más tarde, pero es más fácil que se nos olvide si lo dejamos para después.

fotograma=$(devuelvefotograma $numerofotograma)
let numerofotograma++

Y ya podemos usar la variable fotograma como imagen de destino con convert.

 

La función en un script

 

#!/bin/bash

function devuelvefotograma()
{

# Función que recibe el numeral del último fotograma creado y devuelve el fotograma a utilizar como imagen destino por convert


    esentero='^[0-9]+$'
    numerofotograma=$1
    
    if [ -z $numerofotograma ] || ! [[ $numerofotograma =~ $esentero ]]
    then
        let numerofotograma=1
    fi
    

    if [ $numerofotograma -lt 10 ]
    then
        fotograma="fotograma000"$numerofotograma".png"
    
    elif [ $numerofotograma -ge 10 ] && [ $numerofotograma -lt 100 ]
    then
        fotograma="fotograma00"$numerofotograma".png"
    elif [ $numerofotograma -ge 100 ] && [ $numerofotograma -lt 1000 ]
    then
        fotograma="fotograma0"$numerofotograma".png"
    else
        fotograma="fotograma"$numerofotograma".png"
    fi

    echo $fotograma;
}

for i in $(seq 1 50)
do
    fotograma=$(devuelvefotograma $numerofotograma)
    let numerofotograma++
    echo "El fotograma es: "$fotograma
done

 

Este es un script de control, para ver que devuelve bien el nombre del fotograma. Usa cualquier parámetro de convert para generar los fotogramas con las modificaciones que desees.

Publicado en Programación

Uno de los mejores compañeros de viaje de ImageMagick a la hora de procesar vídeo es ffmpeg.

ffmpeg es un programa de edición de vídeo que permite, desde la línea de comandos crear vídeos, editarlos, extraer el audio, combinar una pista de audio y otra de vídeo generadas individualmente en una mismo fichero... Tiene todas las funcionalidades de cualquier programa de edición de vídeo (la mayoría de los programas de edción de vídeo en modo gráfico se basan en ffmpeg para procesar vídeos y lo que hacen es que visualmente sea un poco más amigable) con la ventaja de ser en modo consola, por lo que permite automatizar procesos y usarlo en scripts, como contrapartida, es un poco farragoso de usar y no tan cómodo de trabajar como Kdenlive, OpenShot, Pitivi u otro programa gráfico.

Pero ahora vamos a ver cómo sacarle mucho partido en combinación con ImageMagick descomponiendo un vídeo en fotogramas para poder procesar individualmente cada uno de ellos con IM, componiendo una serie de fotogramas en vídeo y generando un vídeo al vuelo en un script sin tener que almacenar los fotogramas en el disco y luego generar el vídeo que, como comenté al explicar qué son convert y mogrify, muchas veces nos genera un gran quebradero de cabeza cuando hacemos un vídeo procesando uno a uno los fotogramas con ImageMagick.

 Descomponer un vídeo en fotogramas

Para descomponer en fotogramas un vídeo le tenemos que indicar a ffmpeg el fichero de entrada con -i y los ficheros de salida con, al igual que cuando generamos nuevas imágenes con crop, el formato de salida se lo daremos con un prefijo, el indicador del formato del numeral con % y la extensión del fichero. Algo así como:

ffmpeg -i video.mp4 fotograma%04d.png

 Lo que nos generará es una serie de fotogramas que se llamarán fotograma0001.png, fotograma0002.png... ya que le hemos indicado:

  • Un prefijo según un patrón. En este caso "fotograma"
  • Que añada un número correlativo en cada fotograma de cuatro dígitos (%04d)
  • Un formato. En este caso, al indicarle la extensión .png generará los fotogramas en formato PNG.

 

Componer un vídeo a partir de una secuencia de imágenes

Del mismo modo que podemos descomponer en fotogramas un vídeo, podemos componer un vídeo a partir de fotogramas. Para que el vídeo tenga el orden correcto de fotogramas, lo mejor es que sigan el patrón que he comentado antes: el mismo prefijo, números correlativos y con la misma cantidad de dígitos y la misma extensión. Esto no es obligatorio, ya que podríamos indicarle que generase un vídeo, por ejemplo, con todos los pngs de un directorio (*.png), pero molesta mucho ver cómo un vídeo que has tardado horas en renderizar falla el orden de algún fotograma simplemente por no haber nombrado con un patrón claro los fotogramas. Así que haremos las cosas bien y seremos más felices:

ffmpeg -i fotograma%04d.png video.mp4

En general, con este comando genera un vídeo a partir de los fotogramas, aunque, como digo, si le decimos exactamente cómo queremos el vídeo, lo hará exactamente como queremos. Así que le podemos añadir alguna opción para que haga el vídeo a nuestro gusto:

-r $fotogramasporsegundo: con la opción -r le indicamos el ratio de fotogramas por segundo que queramos que tenga el vídeo.

-s $anchuraX$altura: con -s indicamos el tamaño del vídeo

-aspect $ancho:$alto: el aspecto del fotograma, por ejemplo, 16:9. Opción que la inico aquí más a modo de curiosidad que por practicidad, ya que si le indicamos el tamaño, le estamos indicando el aspecto.

-c:v $codecdevideo: con -c:v le indicamos el códec de vídeo con el que queremos que renderice el vídeo (Nota: -c:a es para audio -c:v es para vídeo)

-pix_fmt $formatodelpixel: -pix_fmt permite seleccionar el formato de píxel. Podemos ver todos los formatos seleccionados con ffmpeg -pix_fmts que nos muestra el nombre de formato de píxel, los bits por píxel de ese formato y los componentes NB (el número de componentes de una imagen, por ejemplo, los tres canales RGB).

 Componer al vuelo un vídeo a través de los fotogramas generados

Para componer un vídeo al vuelo a través de fotogramas generados en un script con convert, le debemos indicar a convert en lugar de un nombre de fichero, que los codifique como png:- y a ffmpeg, que recoja los ficheros con image2pipe. Quedaría algo así:

#!/bin/bash

for i in $lista
do
     convert imagen.png -$parametro $valor png:-

done | ffmpeg -f image2pipe -i - video.mp4

 

Aquí también le podemos indicar a ffmpeg los valores que deseemos para ajustar su trabajo a nuestras necesidades.

 

Nota: Gracias a Gaspar Fernández (https://poesiabinaria.net) por sus indicaciones con image2pipe.

Publicado en Multimedia
Sábado, 25 Agosto 2018 11:25

Dados cargados en $RANDOM

Ya hemos visto que $RANDOM%$limitesuperior no funciona.

Hemos visto que $RANDOM%1 para hacer tiradas "a cara o cruz" no funciona.

Y del mismo modo que deberemos sospechar (y no apostar) si vemos que un trilero siempre saca el mismo resultado lanzando una moneda, cuando lanza un dado puede que haga también trampa. Los dados se pueden cargar y hacer que un lado pese más, por lo que hay más posibilidades de que ese lado sea el que se apoye en la mesa y, por lo tanto, sea el lado apostado el que quede arriba. Pasa lo mismo con $RANDOM:

#!/bin/bash

let nocoincide=0

for i in $(seq 1 1000)
do
    for x in $(seq 1 1000)
    do
       let numero=$((RANDOM%$x))
       if [ $numero -lt 10 ]
       then
            echo $numero >> coincidencias.txt
       fi
    
    done
done

for i in $(seq 0 9)
do
    echo "Veces que se repite "$i
    fgrep -o $i coincidencias.txt | wc -l
done

 

El resultado que me ha dado es (cada vez que lo probemos saldŕa algo distinto, ya que son números aleatorios):

Veces que se repite 0
7559
Veces que se repite 1
6668
Veces que se repite 2
5941
Veces que se repite 3
5730
Veces que se repite 4
5387
Veces que se repite 5
5219
Veces que se repite 6
5053
Veces que se repite 7
4810
Veces que se repite 8
4769
Veces que se repite 9
4638

 

Cuanto más pequeño es el número, más veces se repite. Curioso caso de "aleatoriedad". ¿No os resulta sospechoso? A mi, sí. Por lo que voy a compararlo con otros números. Y antes, voy a borrar coincidencias.txt para evitar viciar resultados:

rm coincidencias.txt

Y ahora, el script:

#!/bin/bash

let nocoincide=0

for i in $(seq 1 1000)
do
    for x in $(seq 1 1000)
    do
       let numero=$((RANDOM%$x))
       if [ $numero -lt 10 ]
       then
            echo $numero >> coincidencias.txt
       elif [ $numero -eq 100 ]
       then
            echo $numero >> coincidencias.txt
       elif [ $numero -eq 500 ]
       then
            echo $numero >> coincidencias.txt
       elif [ $numero -eq 750 ]
       then
            echo $numero >> coincidencias.txt
       elif [ $numero -eq 999 ]
       then
            echo $numero >> coincidencias.txt
       fi
    
    done
done

for i in $(seq 0 9)
do
    echo "Veces que se repite "$i":"
    fgrep -o $i coincidencias.txt | wc -l
done

echo "Datos de control"
for i in 100 500 750 999
do
    echo "Veces que se repite "$i":"
    fgrep -o $i coincidencias.txt | wc -l
done

Y el resultado:

Veces que se repite 0:
13717
Veces que se repite 1:
8694
Veces que se repite 2:
5986
Veces que se repite 3:
5651
Veces que se repite 4:
5389
Veces que se repite 5:
6259
Veces que se repite 6:
5029
Veces que se repite 7:
5339
Veces que se repite 8:
4796
Veces que se repite 9:
4701
Datos de control
Veces que se repite 100:
2296
Veces que se repite 500:
687
Veces que se repite 750:
277
Veces que se repite 999:
0

 

Ummmm... Como digo, algo que es aleatorio puede cambiar el resultado. Pero si siempre que ejecutamos el script nos da el mismo patrón, que es que cuanto más pequeño sea el número, más veces sale, es que esa aleatoriedad está tan viciada con los dados cargados de un trilero. Y es que $numero en $RANDOM%$numero no indica el límite superior sino el divisor de un dividendo aleatorio en una instrucción en la que le pedimos que nos indique el resto.

Ni más, ni menos.

Publicado en Programación
Sábado, 25 Agosto 2018 10:57

Más sobre la aleatoriedad de $RANDOM

En otro artículo ya comenté que para hacer una especie de "cara o cruz" en el que de forma aleatoria nos muestre 0 o 1, $RANDOM%1 no funciona, ya que siempre da 0. En un comentario me decían que dividir una cantidad entre 1 no da decimales. Es cierto, nunca podrá haber rendondeo a la alza porque nunca podrá haber redondeo y, por lo tanto, nunca podrá salir la cantidad indicada como límite superior del rango.

Voy a hacer un script en el que saquemos muchos números aleatorios. Por ejemplo, que mil veces haga una tirada aleatoria con resultados del 0 al 1.000. 

#!/bin/bash

for i in $(seq 1 1000)
do
    for x in $(seq 1 1000)
    do
       let numero=$((RANDOM%$x))
       if [ $numero -eq $x ]
       then
            echo $x
       fi
    done
done

Al ejecutarlo no sale nada. Y repito, y repito, y repito la ejecución del script. Siempre sin ningún resultado. ¿Me habré equivocado? Voy a acumular las veces que el resultado no coincide con el límite superior:

#!/bin/bash

let nocoincide=0

for i in $(seq 1 1000)
do
    for x in $(seq 1 1000)
    do
       let numero=$((RANDOM%$x))
       if [ $numero -eq $x ]
       then
            echo $x
       else
            let nocoincide++
       fi
    
    done
done

echo "Han salido "$nocoincide" coincidencias con el límite superior"

Ahora el resultado siempre es el mismo:

Han salido 1000000 coincidencias con el límite superior

Pues igual no he sido yo el que me he equivocado. Aunque es cierto que al ser aleatorio puede que ese número no salga. Pero si varias veces repito un millón de tiradas y nunca coincide, algo raro pasa. Quizá lo raro es que quien afirma que para sacar un número aleatorio entre 0 y $x se puede conseguir con let numero=$((RANDOM%$x)) se equivoca... o que nunca se ha parado a comprobarlo.

Publicado en Programación

Cuando queremos escribir en un fichero de texto desde un script de Bash, tenemos dos opciones:

Que queramos sobreescribir el fichero con el texto que le enviemos

Que queramos anexar el texto a un fichero ya existente

La primera opción la haremos con:

echo $variable > fichero.txt

La segunda opción, con >>:

echo $variable >> fichero.txt

Ejemplos

Si queremos escribir únicamente el último resultado:

#!/bin/bash

for i in $(seq 1 100)
do
     echo $i > numeros.txt
done

 

Si queremos un fichero en el que se almacene una lista de números del uno al cien:

#!/bin/bash

for i in $(seq 1 100)
do
     echo $i >> numeros.txt
done

Publicado en Programación

Si queremos un número aleatorio en Bash, tenemos la función de Bash RANDOM. Es una función del intérprete de comandos, por lo que no lo podemos ejecutar como comando, sino que si queremos desde la línea de comandos un número aleatorio, deberemos escribir:

echo $RANDOM

Esto nos dará un número aleatorio entre 0 y 32.768 (2 elevado a 15).

Pero, ¿qué pasa si queremos delimitar el rango en el que queremos el número aleatorio?

Podemos dividirlo por el límite superior y, al devolver el módulo, siempre será, como máximo, el número indicado menos uno. En muchos artículos y tutoriales  que dicen que el número que indicamos después del símbolo de porcentaje es el límite superior, pero esto no es así.

Veamos un caso extremo:

#!/bin/bash

contador=0
for i in $(seq 1 100000)
do
    let numero=$((RANDOM%1))
    if [ $numero -eq 1 ]
    then
        let contador=$contador+1
    fi
done
echo $contador

 

Le digo que haga un bucle cien mil veces y que calcule un número aleatorio entre el 0 y el 1. Que cuente cuantas veces sale 1 y muestre el número de veces que ha salido 1.

El resultado siempre es 0.

Así pues, cuando queráis un número aleatorio con un rango, sumadle uno al rango superior que le indiquéis a $RANDOM.

Publicado en Programación

Vamos a ver cómo calcular todos los divisores de un número. Esto nos puede servir, por ejemplo para calcular en cuantas piezas iguales podemos dividir un fotograma. Veamos un script que lo hace:

#!/bin/bash

function hallatodoslosdivisores()
{
    divisores=""
    for i in $(seq 1 $1)
    do
        let resto=$1%$i
        if [ $resto -eq 0 ]
        then
            divisores=$divisores$i" "
        fi
    done
    echo $divisores
}
let numero=1920
todoslosdivisores=$(hallatodoslosdivisores $numero)
echo "Los divisores de "$numero" son: "$todoslosdivisores

Explicación del script:

En una función llamada hallatodoslosdivisores, le indicamos que cree una variable vacía para poder ir rellenando de las cadenas que le digamos según si cumplen o no el requisito que buscamos. Después le decimos que recorra desde 1 hasta el número que le indicamos y que calcule el módulo, es decir, el resto de la división. Si el resto es 0, es que ese número es divisor del parámetro que le hemos indicado, así que se deberá incluir en el listado. En esa instrucción (divisores=$divisores$i" ") le digo que anexe también un espacio en blanco, así podemos separar fácilmente los divisores. Una vez recorrido desde 1 hasta el número indicado y hallados todos los divisores de ese número, que la función devuelva el resultado para poder trabajar con él.

Le indicamos un número. En este caso, 1920 por ser la anchura en píxeles del formato HD, pero le podemos indicar cualquier otro número. Para enviar un parámetro a una función y luego recibir en una variable el resultado de esa función escribimos:

variable=$(funcion $parametro)
Y, por último, comprobamos que el resultado es correcto.

¿Lo comprobamos? Aquí está:

Los divisores de 1920 son: 1 2 3 4 5 6 8 10 12 15 16 20 24 30 32 40 48 60 64 80 96 120 128 160 192 240 320 384 480 640 960 1920

 

Publicado en Programación
Página 1 de 3

¡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í