Archivo

Entradas Etiquetadas ‘sed’

C.I. XVII: Historia de C por Denis Ritchie, tareas elefante, Raspberry PI, NVIDIA y la Linux Foundation, sed, urandom en python

Domingo, 11 de Marzo de 2012 Gaspar Fernández 1 comentario

Mucho tiempo sin una sección de estas, y traigo contenidos muy variados:

Números grandes en C usando GMP. Resolución del primer reto de #tuentiContest (Super Hard Sum)

Viernes, 24 de Junio de 2011 Gaspar Fernández Sin comentarios

Aquí llega mi primera aportación a las soluciones de los retos del I concurso de programación de Tuenti. La utilización de números grandes es algo que siempre me llamó la atención, y normalmente utilizo bc cuando necesito algún cálculo. Este reto se podía resolver con bash/sed/bc y, aunque varios lenguajes permiten la utilización de números de precisión arbitraria “de serie”  como python y Java, yo decidí hacerlo en C, utilizando la biblioteca GMP.

En un lenguaje como C, es normal que no podamos utilizar números de precisión arbitraria con los operadores normales (+, -, *,…), en este caso tendremos que hacer llamadas a funciones de la biblioteca para realizar las operaciones, tampoco podremos utilizar un printf() normal para mostrarlos.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
*************************************************************
* @file hardsum.c
* @brief Tuenti Contest Test Phase
* Sum numbers separated by space line by line
*
* @author Gaspar Fernández <blakeyed@totaki.com>
* @version 0.0.2
* @date 12 jun 2011
*
* http://totaki.com/poesiabinaria
*
*************************************************************/


#include <stdio.h>
#include <string.h>
#include <gmp.h>

/* Huge string */
#define STRSIZE 1000

int main()
{
  char bigstr[STRSIZE];
  mpz_t tmp, sum;
  char * token;

  /* Initialize gmp numbers */
  mpz_init(tmp);
  mpz_init(sum);
 
  /* Read until EOF in stdin */
  while (fgets(bigstr, STRSIZE, stdin)!=NULL)
    {
      /* reset sum */
      mpz_set_si(sum, 0);
      token=strtok(bigstr, " \n");
      while (token!=NULL)
        {
          gmp_sscanf(token, "%Zd", &tmp); /* Extract number from token string */
          mpz_add(sum, sum, tmp);         /* Adds numbers */
          token=strtok(NULL, " \n");
        }
      gmp_printf("%Zd\n", sum);
    }

   return 0;
}

Para compilar, debemos incluir gmp:

$ gcc -o hardsum hardsum.c -lgmp

Para utilizar este tipo de variables numéricas, primero tendremos que inicializarlas con mpz_init(), otras funciones interesantes son:

  • mpz_set_si(): inicializa el número con un valor entero.
  • gmp_sscanf(): igual que scanf(), pero con la posibilidad de utilizar estas nuevas variables.
  • mpz_add(): realiza la suma de dos números
  • gmp_printf(): igual que printf(), pero con la posibilidad de utilizar estas nuevas variables.

GMP tiene muchísimas funciones para realizar gran cantidad de operaciones, se puede consultar la documentación aquí.

Instalando el parche milagroso para linux [ SCHED_AUTOGROUP ]

Jueves, 18 de Noviembre de 2010 Gaspar Fernández 3 comentarios

Hace unos días se publicó la noticia de un parche milagroso que aumentaba el rendimiento de Linux en el escritorio en varios medios. Este parche mejoraba el planificador de tareas haciendo que nuestra experiencia de usuario sea más fluida, especialmente cuando estamos ejecutando muchas cosas al mismo tiempo.

Bien, he querido hacer una pequeña guía de instalación del parche. Aunque está hecha en Arch Linux es fácilmente adaptable a cualquier distribución:

Descargar y preparar un kernel actualizado

El parche está pensado para la versión 2.6.36 y aunque seguro que es posible instalarlo en una versión más antigua (en mi ordenador principal tengo una 2.6.25 y hay que liarla, ya que el parche necesita muchas características  de versiones más nuevas)

Lo primero es crear en nuestro home (~) un directorio para hacer todo el proceso, por ejemplo linuxplay (muchos prefieren descargar y compilar en kernel en /usr/src (y también es la Gentoo way), pero vamos a intentar pasar el mayor tiempo posible como usuario y el menor tiempo como root:

~$ mkdir linuxplay

Para descargar la última versión (Noviembre 2010), la 2.6.36:

~$ cd linuxplay

~/linuxplay $ wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.36.tar.bz2

Cuando terminemos de descargarlo, lo descomprimimos:

~/linuxplay $ tar xvjf  linux-2.6.36.tar.bz2

Ya tenemos el código fuente de Linux descomprimido y ahora tenemos que crear una configuración similar a la que tenemos, pero en el nuevo kernel:

# Entramos en el directorio donde se ha descomprimido el kernel

~/linuxplay $ cd linux-2.6.36

# Hacemos limpieza de configuraciones anteriores, si acabamos de descargar el kernel no hace

# falta, pero más vale prevenir.

~/linuxplay/linux-2.6.36 $ make mrpropper

# Copiamos la configuración anterior del kernel… puede que algunas distribuciones no nos

# dejen hacer esto, debemos mirar en el manual, o buscar el archivo de configuración, tal vez en /boot/

~/linuxplay/linux-2.6.36 $ zcat /proc/config.gz > .config

Descargar, adaptar y parchear el kernel

Primero bajamos el parche desde aquí: Versión 3 Nov 2010 y lo copiamos en ~/linuxplay/linux-2.6.36/ (el archivo se llama RFC-RFT-v3-sched-automated-per-tty-task-groups.patch).

Esto depende del kernel y además es optativo. El parche debe modificar el archivo drivers/tty/tty_io.c y, por ejemplo, yo lo tengo en drivers/char/tty_io.c por lo que, aunque al aplicar el parche nos iba a preguntar dónde está el archivo, podemos, con sed, decírselo desde ahora.

~/linuxplay/linux-2.6.36 $ sed -i ’s/drivers\/tty\/tty_io/drivers\/char\/tty_io/p’ RFC-RFT-v3-sched-automated-per-tty-task-groups.patch

Ok, vamos a aplicar el parche:

~/linuxplay/linux-2.6.36 $ patch -p1 < RFC-RFT-v3-sched-automated-per-tty-task-groups.patch

Configurar el nuevo kernel

~/linuxplay/linux-2.6.36/ $ make localmodconfig

Esta línea configurará el nuevo kernel como el que ya tenemos, y nos preguntará por novedades optativas que podemos instalar, cuando veamos SCHED_AUTOGROUP decimos que sí, o Y.

También podemos hacerlo de forma más artesana:

~/linuxplay/linux-2.6.36/ $ make oldconfig

~/linuxplay/linux-2.6.36/ $ make menuconfig

Pero de esta forma, tendremos que buscar las novedades a mano, SCHED_AUTOGROUP estará en General.

Compilar el kernel

~/linuxplay/linux-2.6.36/ $ make

# y como root (en Ubuntu o derivadas, podemos usar sudo)

~/linuxplay/linux-2.6.36/ $ make modules_install

Instalar el kernel

Para instalarlo podemos hacerlo de varias maneras, a veces con make install nos vale, pero si queremos controlar el proceso, lo hacemos a mano como dice a continuación (los nombres de archivos pueden variar)

# Donde pone x86 lo mismo puede ser x86_64 dependiendo de vuestra arquitectura

~/linuxplay/linux-2.6.36/ $ cp arch/x86/boot/bzImage /boot/vmlinuz-2.6.36

~/linuxplay/linux-2.6.36/ $ cp System.map /boot/System.map-2.6.36

# Donde pone 2.6.36-ARCH es la versión de vuestro kernel, depende también de la distribución.

# pero una forma fácil de sacarla es hacer: ls /lib/modules/

~/linuxplay/linux-2.6.36/ $ mkinitcpio -k 2.6.36-ARCH -g /boot/kernel26-2.6.36.img

Ok, sólo falta hacer una entrada en vuestro gestor de arranque, aquí muestro un ejemplo para Grub 0.97:

# Como root (o con sudo), y con vuestro editor favorito: nano, emacs, gedit, vi…

~/linuxplay/linux-2.6.36/ $ nano /boot/grub/menu.lst

Necesitamos añadir estar líneas, antes del primer title que encontramos, pero lo mejor que podemos hacer es copiar exactamente las líneas de un kernel que funcione ahora mismo, por ejemplo:

# For booting GNU/Linux
title  GNU/Linux (2.6.35)
root (hd0,0)
kernel /boot/vmlinuz-2.6.35 root=/dev/disk/by-uuid/12345678-9abc-def0-1234-56789abc123456 ro
initrd /kernel26-2.6.35.img

Bien, tenemos que añadir un bloque parecido, y cambiar los datos que vienen por los nuevos; manteniendo el anterior en una línea más abajo podemos cargar el kernel antiguo si algo va mal.

# For booting GNU/Linux
title  GNU/Linux (2.6.36) Parche SCHED_AUTOGROUP
root (hd0,0)
kernel /boot/vmlinuz-2.6.36 root=/dev/disk/by-uuid/12345678-9abc-def0-1234-56789abc123456 ro
initrd /kernel26-2.6.36.img

Guardamos los cambios, reiniciamos y a correr… a reproducir  películas y compilar programas al mismo tiempo que movemos las ventanas sin sentido :)

Now playing… para mplayer

Domingo, 14 de Noviembre de 2010 Gaspar Fernández Sin comentarios

screenshot-14-11-2010-201150Se trata de un script para bash que representará en pantalla información del archivo que se está reproduciendo al mismo tiempo que este se visualiza. Perfecto para un sistema mediacenter.

Requerimientos:

  • bash >=3.0
  • mplayer
  • xosd
  • utilidades de sistema utilizadas: date, sed, tr, cut, sleep

Entre sus características destaca la escritura de un archivo: $HOME/.videolog con los archivos que se reproducen. Uno de los posibles usos es la descarga de muchos vídeos de youtube en un directorio concreto, posterior visualización y borrado de cada uno de los archivos tras su visionado.

Además, si el archivo de audio o vídeo a reproducir contiene metadatos de Artista y Título, se visualizará la información de estos metadatos siempre que no estén en la lista negra (variable $ARTISTAS_PROHIBIDOS), en otro caso visualizaremos el nombre del archivo arreglado (eliminando las cadenas que aparecen en la variable FILENAME_RECORTADO, aquí podemos incluir extensiones o pequeñas anotaciones sobre la calidad o resolución de un vídeo).

Se recomienda modificar XOSD_OPTIONS_ARTISTA, XOSD_OPTIONS_TITULO, XOSD_OPTIONS_INFO y XOSD_OPTIONS_DURACION de acuerdo a los tipos de letra, colores y todo lo que se desee. Dejo una pequeña referencia de las opciones de osd_cat:

–pos Posición del texto: top(arriba), middle(en medio de la pantalla), bottom(abajo)
-A Alineación del texto: left(izquierda), center(centrado), right(derecha)
-c Color: puede ser en notación html #rrggbb o por su nombre
-s Offset o desplazamiento de la sombra
-o Offset o desplazamiento desde la parte superior o inferior de la pantalla
-d Tiempo en segundos que se mantendrá el texto en la pantalla
-f Tipo de letra. Para ver los tipos de letra disponibles ejecutar xfontsel.

Inicio del archivo: mplayernp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#!/bin/bash

##########################################################################
#
# MPLAYER NOW PLAYING version 0.1
# Copyright (C) 2010 by Gaspar Fernández <gaspy at totaki.com>
# http://totaki.com/poesiabinaria
#
##########################################################################

#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License.

#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.

#   You should have received a copy of the GNU General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.

XOSD_OPTIONS_ARTISTA="--pos=bottom -A left -c #fff -o -110 -s 2 -d 10 -f -*-utopia-*-*-*-*-*-520-*-*-*-*-*-*"
XOSD_OPTIONS_TITULO="--pos=bottom -A left -c #fff -o -100 -s 2 -d 10 -f -*-utopia-*-*-*-*-*-420-*-*-*-*-*-*"
XOSD_OPTIONS_INFO="--pos=bottom -A left -c #fff -s 2 -o -80 -d 10 -f -*-utopia-*-*-*-*-*-320-*-*-*-*-*-*"
XOSD_OPTIONS_DURACION="--pos=bottom -A left -c #fff -s 2 -o -60 -d 10 -f -*-utopia-*-*-*-*-*-220-*-*-*-*-*-*"

# Si precalculamos esto, damos velocidad
ESCAPE=`echo -e "\e"`

ARTISTAS_PROHIBIDOS=("virtualdub")
FILENAME_RECORTADO=(".avi" ".flv" ".mp3" ".mp4")

function print_info()
{
    artist="$1"
    title="$2"
    filename="$3"
    width="$4"
    height="$5"
    fps="$6"
    minutos="${7/./,}"      # Si nuestra locale es es_ES debemos sustituir puntos por comas
    segundos="${8/./,}"
    if [[ -n $artist ]]
    then
    artist_text=${info_val[$artist]}
    for proh in ${ARTISTAS_PROHIBIDOS[*]}
    do
        if [[ `echo $artist_text | tr [:upper:] [:lower:]` =~ $proh ]]
        then
        artist="";
        title="";
        break;
        fi
    done
    fi

    if [[ -n $artist ]]
    then
    echo $artist_text | osd_cat $XOSD_OPTIONS_ARTISTA &
    fi
    if [[ -n $title ]]
    then
    title_text=${info_val[$title]}
    echo $title_text | osd_cat $XOSD_OPTIONS_TITULO &
    else
    # Si no tenemos la codificación correcta configurada, esto puede saltar
#   fname=`basename "$filename"`
#   dname=`dirname "$filename"`
#   defname=`ls "$dname/$fname"*`
#   defname=`basename "$defname"`
    defname=`basename "$filename"`
    for recorte in ${FILENAME_RECORTADO[*]}
    do
        defname=${defname/$recorte/}
    done
    echo $defname | osd_cat $XOSD_OPTIONS_TITULO &
    fi
    if [[ -n $fps ]]
    then
    echo $width"x"$height"@"$fps | osd_cat $XOSD_OPTIONS_INFO &
    fi
    duracion=`printf "%1.0f:%1.0f" "$minutos" "$segundos"`
    echo $duracion | osd_cat $XOSD_OPTIONS_DURACION &

    echo "`date +"%d/%m/%Y %H:%M"` Media: $filename Dur: $duracion" >> $HOME/.videolog

}

function keyvalue()
{
    key=`echo "$1" | cut -d= -f1`
    value=`echo "$1" | cut -d= -f2`

    res[0]=$key;
    if [[ -n $value ]]
    then
    res[1]=$value;
    else
    res[1]="0";
    fi

    if [[ -n `echo $key | grep "ID_CLIP_INFO_NAME\|ID_CLIP_INFO_VALUE"` ]]
    then
    # Si tenemos un ID_CLIP_INFO_NAMEx o ID_CLIP_INFO_VALUEx extraemos el x
    info=(`echo $key | sed -n -e "s/\([a-zA-Z_]*\)\([0-9]*\)/\1\n\2/p"`)
   
    res[0]=${info[0]}
    res[2]=${info[1]}
    fi
    echo -e ${res[0]}"\n"${res[1]}"\n"${res[2]}"\n"


}

function tituladora()
{

artist="";
title="";
while read -n 200 dato 
do
    if [[ -n `echo $dato | grep ID_` ]] # Extraemos información de mplayer
    then
    OLD_IFS=$IFS;
    IFS="
"
;
    kval=( `keyvalue $dato` );
#   echo ${kval[0]} "********"
    IFS=$OLD_IFS

    case ${kval[0]} in
        "ID_FILENAME")
        filename="${kval[1]}"          
        ;;
        "ID_VIDEO_WIDTH")
        width=${kval[1]}
        ;;
        "ID_VIDEO_HEIGHT")
        height=${kval[1]}
        ;;
        "ID_VIDEO_FPS")
        fps=${kval[1]}
        ;;
        "ID_LENGTH")
        seconds=${kval[1]};
        # Extrae la duración en minutos y segundos
        duration=( `echo "scale=0; $seconds / 60; scale=0; $seconds % 60" | bc` )
        ;;
        "ID_CLIP_INFO_NAME")
        if [[ `echo ${kval[1]} | tr [:upper:] [:lower:]` == "artist" ]]
            then
#           echo "ARTISTA CAPTURADO "${kval[2]};
            artist=${kval[2]} # Donde encontramos el artista
        else
            if [[ `echo ${kval[1]} | tr [:upper:] [:lower:]` == "title" ]]
            then
            title=${kval[2]} # Donde encontramos el artista
#           echo "TITULO CAPTURADO"
            fi
        fi
        ;;
        "ID_CLIP_INFO_VALUE")
        # Almacenamos el valor obtenido
#       echo "ALMACENO EN "${kval[2]} "ESTO" ${kval[1]} "**" ${kval[0]} ${kval[2]} = ${kval[1]}
        info_val[${kval[2]}]="${kval[1]}"
        ;;
    esac
#   echo ${info_val[@]}
    else
    # Si encontramos caracteres de control....
    if [[ $dato =~ $ESCAPE ]]
    then

        # Tal vez podamos comentar esto para dar velocidad --- INICIO
        if [[ $dato =~ "Position" ]]
        then       
        printf "%s\n" "$dato"
        else
        printf "%s" "$dato"
        fi
        # Tal vez podamos comentar esto para dar velocidad --- INICIO
    else
        if [[ ${dato:0:3} == "AO:" ]] # Aquí empieza el Audio... saltaremos tanto para archivos de audio como
                                      # para vídeos / películas... que también tengan audio
        then
        # Empieza la reproducción
        sleep 1 && print_info "$artist" "$title" "$filename" "$width" "$height" "$fps" "${duration[0]}" "${duration[1]}"
        fi

        echo $dato;
    fi
    fi
done
}
mplayer -identify $@ | tituladora

Por último, para utilizar este programa, podemos crear un alias a mplayer:

alias mplayer=”mplayernp”

Para finalizar dejo algúnos ejemplo de uso (son válidos también para mplayer, ya que mplayernp pasa los comandos tal cual a mplayer:

1
2
# Para reproducir archivos dentro de un directorio con orden aleatorio y en pantalla completa
mplayernp -fs `ls /directorio/*.avi | sort -R`

Vídeo de la foto: El Hombre de Negro - Greenfield

Sed… de venganza (1): Sustituyendo cadenas en múltiples archivos

Lunes, 28 de Junio de 2010 Gaspar Fernández 1 comentario

3846929292_60721fb24e

Es uno de los grandes desconocidos y tan temidos comandos de que disponemos. Y es cierto que a veces da pereza mirarse el manual cuando queremos hacer algo que sed podría hacer rápidamente.

Lo que cuento hoy es su uso más popular (porque sed se puede usar para muuuuuchas cosas) y es muy simple, sustituir en un stream un texto por otro (Donde dije digo, digo Diego).

Imaginemos un fichero de texto, para ser originales llamémosle README, y en el texto queremos cambiar la palabra “Ireland” por “Spain”. Podemos hacer lo siguiente:

$ sed ’s/Ireland/Spain/g’ README

y veremos en pantalla el texto. Para guardarlo en el mismo archivo, si buscamos por Internet, veremos cómo la gente se complica la vida (que no digo que sea malo, yo también me la complico un poco más abajo), pero podemos usar el modificador -i (que tiene algunas funciones curiosas).

Si ahora hacemos:

$ sed -i ’s/Ireland/Spain/g’ README

Los cambios se guardarán automáticamente en el fichero README. Pero si investigamos un poco más, y queremos rematar la faena podemos hacer:

$ sed -i~ ’s/Ireland/Spain/g’ README

En este caso, guardaremos el cambio en el fichero README y grabaremos en README~ una copia de seguridad del fichero antiguo. La extensión de la copia de seguridad podemos cambiarla haciendo por ejemplo:

$ sed -i.bak ’s/Ireland/Spain/g’ README

Para que la copia sea README.bak

Pero ahora viene algo interesante, con el parámetro -i podemos modificar todos los archivos que queramos, sed acepta en la entrada múltiples archivos, por lo que si en un directorio con muchos archivos queremos cambiar un texto (imaginad que habéis hecho un proyecto relativamente grande, y hay una función con un nombre un poco ridículo, curiosamente es la que más veces llamáis, y como vamos a enseñar el código fuente, no queremos que nadie lea eso), podremos hacer:

$ sed -i ’s/nombre_ridiculo/nombre_elegante/g’ *

Ahora bien, si el proyecto está en múltiples directorios, siempre podemos usar find para localizar los archivos de la siguiente forma:

find -name ‘*.c’ -exec sed -i ’s/nombre_ridiculo/nombre_elegante/g’ {} \;

Con toda esta línea, buscaremos todos los archivos con extensión .c dentro del directorio actual y subdirectorios y se los pasaremos a sed, con el modificador -exec de find, ejecutaremos el comando que especificamos, donde {} indica el nombre de archivo (que nos lo da find) y con \; indicamos el fin del comando y sus parametros.

Pero esto no termina aquí, sed soporta expresiones regulares, y si por ejemplo queremos coger todas las imágenes de un fichero html, cambiarlas de directorio y añadirles un class (inicialmente encontramos <img src=”foto.jpg” alt=”" /> , y queremos que salga <img class=”imagen” src=”/static/foto.jpg” alt=”" />) podemos hacer lo siguiente:

sed ’s/src=”\(.[a-zA-Z\.\_\/]*\)”/src=”\/static\/\1” class=”imagen”/g’ fichero.html

Lo que hay en negrita, corresponde a la expresión regular que determina el nombre del archivo (caracteres de la a a la z, de la A a la Z, puntos, guiones bajos, y barras (en la cadena de origen), en la cadena de destino escribimos \1 donde queremos que coloque el texto correspondiente a la expresión anterior, es decir donde queremos que coloque el nombre del archivo.

Ni que decir tiene que podemos hacer una mezcla de todo lo dicho en este post ( expresiones regulares, y sustitución en múltiples archivos dentro de múltiples subdirectorios y guardando backups ), y estaremos delante de una potente herramienta.

Lo malo de ejecutar sed, es que tenemos que escapar muchos caracteres,por lo menos ), (, ., \, / y seguro que encontramos alguno más; para ello, siempre que queramos introducir un carácter de esos, debemos poner una contra barra (\) delante.

Foto: albertopveiga (Flickr)

Descargar álbumes Picasa sin Picasa, sin Java y sin ningún programa extra

Martes, 15 de Junio de 2010 Gaspar Fernández 2 comentarios

fotofotoUn buen sistema para compartir fotos es Picasa, de Google; aunque puede que no seamos usuarios de Google, ni tengamos el programa instalado en nuestro equipo, pero queramos descargar un álbum de fotos por completo.

Presento otro de mis scripts rápidos (no está optimizado, tal vez sea lento, pero hace el apaño) para descargar las fotos de un álbum Picasa. Lo que necesitamos es el RSS del álbum, lo descargamos en algún directorio y ejecutamos el siguiente script:

1
2
3
4
for i in `sed -e 's/\/>/\/>\n/g' archivo.rss | sed -n -e 's/.*<media:content url='"'"'\(.*\)'"'"' height=.*/\1/p'`
do
  wget $i;
done

Donde archivo.rss es el archivo que acabamos de descargarnos. Sólo utilizamos sed para parsear mínimamente el rss y wget para descargar las fotos.

El parseo no es del todo óptimo, primero introducimos saltos de línea y luego, leemos todo lo que empiece por

Foto: dariuszman86 (Flickr)

Visita otras webs de la red