Archivo

Archivo para la categoría ‘Bash’

REISUB y llamadas remotas a Alt+Sysrq

Domingo, 29 de Agosto de 2010 admin Sin comentarios

En muchos sitios, podemos ver esta palabra clave, para muchos RESUIB para otros RESIUB y normalmente REISUB. Y sirve para reiniciar el sistema Linux de forma segura después de que el sistema se congele; de la siguiente forma: Alt+Imprimir Pantalla + R,E,I,S,U,B (no hace falta soltar las teclas Alt + Imprimir pantalla). Cada letra representa una acción del kernel:

  • R (Devuelve el control al teclado unRaw)
  • E (Termina todos los procesos tErm)
  • I (Mata los procesos que queden vivos full kIll)
  • S (Sincroniza los discos Sync)
  • U (Monta todos los sistemas de archivos como sólo lectura Umount)
  • B (Reinicia el ordenador Boot)

Bien, si tenemos acceso físico al ordenador, no hay problema, pero y si estamos enchufados en otra máquina ? Todo está en el fichero especial /proc/sysrq-trigger.

Obteniendo información de los procesos

Enviando a /proc/sysrq-trigger (como root) la letra correspondiente a la acción del kernel vale. Empezaremos pidiendo ayuda:

root $ echo “h” > /proc/sysrq-trigger

root $ dmesg | tail

…. # Nos dirá muchas cosas, sólo nos interesa la última línea
SysRq : HELP : loglevel0-8 reBoot tErm Full kIll saK showMem Nice powerOff showPc show-all-timers(Q) unRaw Sync showTasks Unmount shoW-blocked-tasks

Vemos cómo el kernel a través de dmesg se comunicará con nosotros. Cada letra mayúscula nos indicará una acción diferente, empezaremos obteniendo información sobre la memoria:

root $ echo “m” > /proc/sysrq-trigger

root $ dmesg | tail -n 35

O información sobre tareas bloqueadas:

root $ echo “m” > /proc/sysrq-trigger

root $ dmesg

Más acciones

Incluso podemos lanzar el OOM killer con la siguiente línea:

root $ echo “f” > /proc/sysrq-trigger

Terminar todos los procesos (igual que comentábamos arriba del todo):

root $ echo “e” > /proc/sysrq-trigger

Cambia el nivel de información de dmesg (del 0 al 8):

root $ echo 5 > /proc/sysrq-trigger

Para enviar un REISUB es algo más elaborado:

root $ nohup bash -c “for key in s u b; do echo \$key > /proc/sysrq-trigger; sleep 4; done”

Aunque tendremos que asegurarnos de que las tareas estén muertas, ya que, nuestra conexión ssh, o nuestro terminal, o incluso bash, se mueren al mandar un E o un I al kernel (dando igual el nohup). Por otra parte, la R la podemos quitar, ya que vale para devolver el control al teclado, y estamos desde un equipo remoto.

Seguridad

Pero tanto por nosotros mismos (debemos de protegernos de meter la pata), como los posibles usuarios del ordenador, tal vez no nos interese que puedan pulsar en teclado alguna combinación de teclas que comprometa al kernel. Para ello, tenemos  /proc/sys/kernel/sysrq o directamente el comando sysctl del cual modificamos la propiedad kernel.sysrq; lo haremos de la siguiente manera:

root $ sysctl kernel.sysrq=0 # Para desactivar Alt+SysRq

root $ sysctl kernel.sysrq=1 # Para activarlo

Se pueden activar algunos comandos sólo, dependiendo del número que se indique.

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

Martes, 15 de Junio de 2010 admin Sin 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)

Curioso e interesante (2): Fragmentación en Linux, WikiUnix, convertir documentos desde la línea de comando, Ubuntu más seguro que Windows by Dell

Domingo, 13 de Junio de 2010 admin Sin comentarios

Estos días he estado un poco liado, pero he dejado varias pestañas del navegador abiertas con algunas curiosidades que he encontrado estos días y me han llamado la atención:

  • Lo leí en Muy Linux. Hay controversia en este tema… casi todos decimos que no es necesario, y otros dicen que sólo somos geeks talibanes que ocultamos las carencias de nuestro sistema operativo preferido; pero la realidad es que la fragmentación en los sistemas de archivos más populares de Linux es significativamente menor que en Windows. Podemos ver más información en: Why doesn’t Linux need defragmenting?
  • Conversor de documentos de OpenOffice desde la línea de comandos: unoconv. Es un script en python que nos permite hacer conversiones de documentos en cualquier formato soportado por OpenOffice (necesita OpenOffice instalado y pyUno). Esto nos permitirá por ejemplo automatizar la conversión de formatos.
  • WikiUnix: Es una gran wiki de referencia de comandos y características de los sistemas Unix; un proyecto de la Oficina de Software Libre de la Universidad de Cádiz.
  • Dell afirma que: Ubuntu es más seguro que Windows; mientras Dell, sigue recomendando insistentemente en su web Windows 7…
  • Microsoft se mofa del fondo de Google. Vale que Google se pasó, metiendo un fondo automáticamente, a modo de presentación de su nueva característica; a la gente no le suelen gustar los cambios. Pero Microsoft aprovecha la más mínima para meter baza. Ya vale con las cadenas de Televisión que muestran el logotipo de Windows o una imagen de Internet Explorar cada vez que emiten la imagen de un ordenador; o que invierta en product placement en series como Crónicas Vampíricas y en varios episodios, Jericho, Entre Fantasmas, Smallville, El Internado, Los Protegidos… qué pastón para promocionarse, y la verdad, espero que todos los responsables de esas series hayan cobrado bien, porque si no, tontos de ellos…

Saludos

Bailando con bits: Ver y modificar los bits de un número

Jueves, 10 de Junio de 2010 admin 2 comentarios

Hay muchas formas para hacer esto, pero quizás la más visual (tal vez también útil algunas veces) es la siguiente (se explica más abajo):

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
#include <stdio.h>

typedef struct {
    unsigned int b1:1;
    unsigned int b2:1;
    unsigned int b3:1;
    unsigned int b4:1;
    unsigned int b5:1;
    unsigned int b6:1;
    unsigned int b7:1;
    unsigned int b8:1;
    unsigned int b9:1;
    unsigned int b10:1;
    unsigned int b11:1;
    unsigned int b12:1;
    unsigned int b13:1;
    unsigned int b14:1;
    unsigned int b15:1;
    unsigned int b16:1;
    unsigned int b17:1;
    unsigned int b18:1;
    unsigned int b19:1;
    unsigned int b20:1;
    unsigned int b21:1;
    unsigned int b22:1;
    unsigned int b23:1;
    unsigned int b24:1;
    unsigned int b25:1;
    unsigned int b26:1;
    unsigned int b27:1;
    unsigned int b28:1;
    unsigned int b29:1;
    unsigned int b30:1;
    unsigned int b31:1;
    unsigned int b32:1;

} Tint_bits;

int main()
{
  int numero;
  Tint_bits *bitpack;

  bitpack=(Tint_bits*)&numero;
  numero=63;
  printf ("Dir cos: %X\nDir paq: %X\n", &numero, bitpack);  // Vemos que las direcciones de memoria son idénticas.
  printf ("Numero: %d\n", numero);
  printf ("Bit 1: %d\n", bitpack->b1);
  printf ("Bit 2: %d\n", bitpack->b2);
  printf ("Bit 3: %d\n", bitpack->b3);
  printf ("Bit 4: %d\n", bitpack->b4);
  printf ("Bit 5: %d\n", bitpack->b5);
  printf ("Bit 6: %d\n", bitpack->b6);
  printf ("Bit 7: %d\n", bitpack->b7);
  printf ("Bit 8: %d\n", bitpack->b8);
  printf ("Bit 9: %d\n", bitpack->b9);
  printf ("Bit10: %d\n", bitpack->b10);
  printf ("Bit11: %d\n", bitpack->b11);
  printf ("Bit12: %d\n", bitpack->b12);
  printf ("Bit13: %d\n", bitpack->b13);
  printf ("Bit14: %d\n", bitpack->b14);
  printf ("Bit15: %d\n", bitpack->b15);
  printf ("Bit16: %d\n", bitpack->b16);
  printf ("Bit17: %d\n", bitpack->b17);
  printf ("Bit18: %d\n", bitpack->b18);
  printf ("Bit19: %d\n", bitpack->b19);
  printf ("Bit20: %d\n", bitpack->b20);
  printf ("Bit21: %d\n", bitpack->b21);
  printf ("Bit22: %d\n", bitpack->b22);
  printf ("Bit23: %d\n", bitpack->b23);
  printf ("Bit24: %d\n", bitpack->b24);
  printf ("Bit25: %d\n", bitpack->b25);
  printf ("Bit26: %d\n", bitpack->b26);
  printf ("Bit27: %d\n", bitpack->b27);
  printf ("Bit28: %d\n", bitpack->b28);
  printf ("Bit29: %d\n", bitpack->b29);
  printf ("Bit30: %d\n", bitpack->b30);
  printf ("Bit31: %d\n", bitpack->b31);
  printf ("Bit32: %d\n", bitpack->b32);
 
  bitpack->b9=1;
  printf("Numero= %d\n", numero);
}

Primero creamos un espacio de bits en nuestro registro Tint_bits, con ello, hacemos 32 variables de tamaño 1 bit (con un espacio en memoria de 32bits (lo que es un entero de 32bits). Lo que hacemos para poder consultar los bits, es crear un puntero de este tipo (Tint_bits) que apunte a la dirección de memoria de nuestro número, con ello podremos leer en memoria, los distintos bits del número accediendo a los diferentes miembros (b1->b32), y lo que es mejor, podemos modificarlos (como hacemos al final del programa).

Lo malo de este método es que no podremos acceder a los bits como si de un array se tratase, y que este método no es muy portable, para enteros de 64 bits habría que hacer otro registro por ejemplo, y tendremos problemas para pasar de un sistema big-endian a un little-endian y viceversa; pero, como yo digo podemos ver la memoria directamente, que a veces es interesante.

Bucles for en BASH

Martes, 1 de Junio de 2010 admin 1 comentario

loooop

No por ser un lenguaje de script enfocado a la línea de comando vamos a dejar de poder hacer un bucle. Es más, si los archivos batch pueden, estos scripts no van a ser menos. Es común ver un bucle for en bash de este modo:

1
2
3
4
for i in $lista;
do
   echo $i;
done

Donde lista puede ser:

lista=”Una serie de cosas separadas por un espacio normalmente. Es un carácter del $IFS

El IFS es el Internal Field Separator (Separador Interno de Campo) y se usa para saber cuándo parar un read; por defecto se usa el espacio/tabulador/nueva línea. En nuestro caso será el separador de los objetos de la lista.

Por ejemplo con este bucle for podemos listar las posibles frecuencias de nuestro procesador (sólo si es compatible con cpufreq y tenemos el módulo del kernel cargado):

1
2
3
4
for j in `cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies`
do
echo "Frecuencia: "$j" Hz"
done

Es decir, hacemos que nuestra lista sea el resultado de la ejecución de “cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies

Este método se parece mucho al for each que tienen muchos lenguajes.

Pero, ¿ qué tal el bucle for de toda la vida? ¿ Ése en el que contábamos de un número hasta otro número ? Podemos hacerlo de dos formas:

for i in ….

1
2
3
4
for i in `seq 4 90`
do
   echo $i
done

Donde en seq podemos colocar el número de inicio y el de fin, uno detrás de otro, si ejecutamos seq en el terminal generará una salida con un número en cada línea (aunque se puede cambiar con -s). Aunque también podremos modificar el incremento (2, 3, 4…). Por ejemplo:

$ seq 1 10 1000

que contará de 1 a 1000 de 10 en 10: 1..11..21..31…….991 (hasta 1000 no puede llegar porque se pasa)
Si queremos contar hacia atrás debemos especificar este incremento negativo:

$ seq 10 -1 0

que contará de 10 a 0: 10..9..8..7…….0

El método tradicional

1
2
3
4
for (( i=0; i<1000; i++ ))
do
   echo $i
done

¡ Anda ! Igual que en C, pero con dos paréntesis… además, éste método lo podemos extender un poco más. Lo mismo que podemos hacer:

for (( i=0; i<1000; i=i+5 ))

Para contar de 5 en 5

for ((i=1000; i>0; i=i-5))

Para contar de -5 en -5

podemos hacer lo siguiente:

for (( i=1000; i>0; i=`expr $i / 2`))

Para ir dividiendo el número entre dos, o:

for (( i=1; i<100; i=`expr $i \* 2`))

para ir multiplicando entre dos

En definitiva, cualquier operación que podamos hacer desde la línea de comando, por ejemplo con expr, aunque si se nos queda corto siempre podemos usar bc (haré un algún post sobre bc).

Con expr podemos hacer algunas operaciones matemáticas simples (suma, resta, multiplicación, división, resto, and y or) con los siguientes símbolos respectivamente (+, -, *, /, %, &, |), aunque *, & y | deben ser escapados con una \ (contra barra).
Cada elemento en la expresión debe ir con un espacio, dejo como ejemplo las siguientes expresiones:

$ expr 100 \& 0
0
$ expr 100 \& 1
100
$ expr 0 \& 3
0
$ expr 0 \| 3
3
$ expr 23 \* 45 + 20 - 4 % 3
1054
$ expr 3 % 2
1
$ a=3
$ expr $a + 1
4

Es cierto que expr hace muchas más cosas: podemos poner paréntesis para dar preferencia a algunas operaciones, y hay palabras clave para operar con cadenas de caracteres.

Foto: Spookuygonk (Flickr)

Saber si estamos conectados a internet [bash]

Miércoles, 26 de Mayo de 2010 admin Sin comentarios

cat_linuxA menudo lanzo scripts que necesitan saber si la conexión a Internet está disponible para lanzarse, en caso de que no lo esté, invertirán mucho tiempo en terminar o terminarán con muchos errores. La forma más fácil de saber cuándo estamos conectados es intentar acceder a un ordenador que sepamos seguro que está conectado… por ejemplo google.com, que para eso está.

Podemos por ejemplo hacer ping al servidor, pero un ping es muy visual, necesitaremos hacer algo más para aprovechar la salida de ese ping; aunque también podemos intentar conectar por el puerto 80 (http).

Dejo varios métodos para poder hacerlo de forma sencilla desde la línea de comandos:

ping

$ if ping -c1 google.com &>/dev/null; then echo “Tienes conexion”; else echo “no tienes conexion”; fi

Con esta línea haremos un ping a google, sólo mandaremos un paquete (-c1) y mandaremos la salida de ping a /dev/null (no nos interesa lo que nos diga, queremos hacer un script amigable al usuario, sin mensajes raros), si ping no da errores, se ha hecho bien, mostramos el mensaje de tienes conexion, si no, el de no tienes conexión.

Aunque en los siguientes scripts haremos una salida de texto, siempre podremos hacer un exit y terminar el script cuando no haya conexión.

netcat

if netcat -z google.com 80; then echo “Tienes conexion”; else echo “no tienes conexion”; fi

Igual que antes pero probamos la conexión al puerto 80, netcat utiliza el parámetro -z para ver sólo si se puede conectar, una vez se conecta, se cierra la conexión.

escribiendo en el servidor directamente

Tenemos dos métodos más…

if echo “”>/dev/tcp/totaki.com/80; then echo “Tengo conexion”; else echo “no tengo”; fi

Aquí conectamos con el servidor a través de /dev/tcp (necesitamos tener permisos), al servidor le enviamos una cadena vacía.

También podemos hacer:

if exec 3>/dev/tcp/totaki.com/80; then echo “Tengo conexion”; else echo “no tengo”; fi

Utilidades y notas

Podemos utilizarlo por ejemplo en cron scripts que requieran conexión a internet (subir una copia de seguridad a un servidor externo, enviar nuestra ip de Internet a un servidor), o por ejemplo para saber la disponibilidad de un servidor, es decir, si tenemos alquilado un servidor a lo mejor nos interesa monitorizarlo para saber si está caído, en fin los usos son los que nos de la imaginación.

Antes dije que podríamos incluir un exit cuando el script no tenga conexión, pero también podremos llamar a otro script en el caso de tener conexión, o hacer lo siguiente (con el ejemplo de ping):

1
2
3
4
5
6
7
8
#!/bin/bash
if ping -c1 google.com &>/dev/null;
then
        echo "Ejecutando script";
        $@
else
        echo "no tienes conexion";
fi

Llamamos al fichero internet, damos permisos de ejecución y podremos llamar a cualquier script de la siguiente forma:

$ internet wget http://www.totaki.com/poesiabinaria

(por ejemplo), el script sólo se ejecutará si estamos conectados a Intenet

Mejoras

Bueno, puede pasar, que alguna vez google.com esté caído, podemos intentar pasar por dos o tres servidores, si vemos que uno de ellos responde (siempre que no sea de una red local) sabremos que estamos conectados.

Foto: fotohiro (Flickr)

Uso de llaves en BASH

Sábado, 15 de Mayo de 2010 admin 1 comentario

llaves
Leo en el blog de Thalskarth (proveniente de Tux Files, que a su vez venía de Slice of Linux) un truco para hacer copias de seguridad de un archivo con bash de la siguiente forma:

cp archivo{,.bk}

Lo que hacemos es parecido a escribir esto otro:

cp archivo archivo.bk

Por lo que podemos intuir fácilmente para qué valen las llaves en este contexto: replicar alternativas. Es decir escribiremos lo que hay antes de la llave, y lo terminaremos con cada una de las opciones de dentro de las llaves que están separadas por comas. Y lo más fácil para entender esto es utilizar echo.
Probaremos lo siguiente:

$ echo “Voy a pintar mi casa de “{verde,azul,rojo,amarillo}
Voy a pintar mi casa de verde Voy a pintar mi casa de azul Voy a pintar mi casa de rojo Voy a pintar mi casa de amarillo

Bien, el mensaje se replica con un espacio entre réplicas. Podemos ahora probar algo más:

$ echo -e “Voy a pintar mi casa de “{verde,azul,rojo,amarillo}”.\n”
Voy a pintar mi casa de verde.
Voy a pintar mi casa de azul.
Voy a pintar mi casa de rojo.
Voy a pintar mi casa de amarillo.

Además, podemos ver que la llave no tiene por qué estar al final del parámetro, podemos ponerla en mitad y sigue funcionando. Hay un espacio al principio de la línea, como mencioné antes, las frases irán separadas por un espacio (es normal, las llaves nos sirven para introducir nuevos parámetros). Podremos solucionarlo con \b (backspace).

echo -e “\bVoy a pintar mi casa de “{verde,azul,rojo,amarillo}”.\n”
Voy a pintar mi casa de verde.
Voy a pintar mi casa de azul.
Voy a pintar mi casa de rojo.
Voy a pintar mi casa de amarillo.

Antes de nada un apunte, no debemos dejar espacios dentro de las llaves, ni entre las comas, ni dentro de cada opción, no olvidemos que son parámetros, aunque sí que podríamos poner un espacio si éste va entre comillas (igual que ocurre con los parámetros).

Crear PDFs

Y a partir de aquí, sólo necesitamos imaginación, por ejemplo podemos ver cómo lo usamos para crear un pdf con imágenes en jpeg (de una carpeta llamadas test-N.jpg). Lo creamos con ImageMagick y sólo queremos de la 1 a la 12:

$ convert test-{?.,10.,11.,12.}jpg todos.pdf

Aunque hay un método mejor, {} (las llaves) soportan rangos, por lo que podemos hacer:

$ convert test-{1..12}.jpg todos.pdf

Comprimir directorios

Podemos, por ejemplo crear un archivo comprimido de un directorio con el mismo nombre de la siguiente manera:

$ tar cvjf test{.tar.bz2,/}

como sustitución a:

$ tar cvjf test.tar.bz2 test/

Diferencias

Encontrar la diferencia de un archivo con su backup (suponemos que el backup es el mismo nombre terminado en ~ (tilde de la ñ):

$ diff test{,~}

O para diferencias rutas (recordemos que podemos poner llaves entre parámetros:

$ diff ~/proyectos/www/{proyecto1,proyecto2}/www/lib/my_lib.h

Que es lo mismo que:

$ diff ~/proyectos/www/proyecto1/www/lib/my_lib.h ~/proyectos/www/proyecto2/www/lib/my_lib.h

Lectura de datos en scripts

Para leer desde la entrada estandar tenemos read, y si queremos introducir cada palabra en una variable podemos usar read palabra1 palabra2 palabra3, y si queremos que estas variables tengan un prefijo común:

$ read palabra{A,B,C}

Combinaciones y juegos

Vamos a hacer múltiples sumas con bc:

$ echo -e {1..4}”+”{4..1}”\n” | bc

Esto pondrá en pantalla el resultado de: 1+4, 1+3, 1+2, 1+1, …, 4+3, 4+2, 4+1.
Con esto vemos que los rangos no sólo van en incremento sino también en decremento.
Pero aún más si hacemos:

echo test{a..z}

Nos completará con testa testb testc…testx, testy, testz

Por último, un ejemplo más complicado, y que, aunque pocas veces nos sirva (más que nada por no acordarnos), ahí queda, llaves anidadas:

$ echo test-{1{10..12},3{9..1}}
test-110 test-111 test-112 test-39 test-38 test-37 test-36 test-35 test-34 test-33 test-32 test-31

Tenemos la posibilidad de introducir opciones dentro de otras opciones y todas se representarán seguidas. ¿Tal vez nos sirva alguna vez para crear un fichero de texto con datos de prueba? Para crear un archivo con temperaturas de varias ciudades:

$ echo -e “\b”{”Madrid 1″{1..4},”Barcelona 1″{3..5},”Malaga “{19..22},”Sevilla 2″{3..4}}”\n” > test

Esto creará un fichero llamado test con el siguiente contenido:

Madrid 11
Madrid 12
Madrid 13
Madrid 14
Barcelona 13
Barcelona 14
Barcelona 15
Malaga 19
Malaga 20
Malaga 21
Malaga 22
Sevilla 23
Sevilla 24

Foto: bohman (Flickr)

Descargar automáticamente todos los programas de Redes

Domingo, 9 de Mayo de 2010 admin Sin comentarios

neuron
Apenas veo la televisión, pero hay ciertos programas que son interesantes y merecen la pena como Redes. Y tampoco me gusta verlos desde la web ya que Flash es muy lento, y me gusta tener lo que veo echar hacia atrás y hacia alante (como hace mplayer) y verlo cómodamente.

Para ello, lo más cómodo es descargarlos, pero cómo descargarlos si tengo que bajarlos uno a uno (y son muchos), y tengo que mirar dónde está el archivo de vídeo (lo primero que nos podemos bajar a mano es una archivo de metadatos que nos dirá dónde está el vídeo), es una tarea muy lenta para hacerla a mano. ¿ Por qué no automatizar el proceso ?

Vemos que desde la web de Redes para la Ciencia nos podemos descargar los programas desde 2008 (lástima que los anteriores no estén disponibles en vídeo desde esta web), y éstos están alojados en Smartplanet (blip.tv). Con estos datos, he confeccionado este script (aún en beta, no es muy estable, ni está optimizado, pero nos hace el apaño).

Si observamos los pasos intermedios de este script, y vemos el fichero de metadatos por dentro, veremos cómo podemos ver más información, descargar el archivo en mov o mp4 (a gusto del consumidor), también encontramos un resumen del programa; os invito a hacer pruebas y comentarlas en este post.

Una posible mejora a corto plazo, sería poner en orden la variable get_years y que, si descubre que varios capítulos han sido descargados, no intente bajar más (a la hora de descargar el último capítulo también con el script), o incluso almacenar en un archivo el número del último capítulo descargado, para así buscar el siguiente en la siguiente ejecución… todo se andará; por ahora, os dejo el script así, que con un poco de cuidado funciona bien.

Y otra cosa más, con un poco de suerte, para el año que viene, sólo tendremos que añadir a la variable get_years el link del blog con los enlaces a los capítulos del año 2011.

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
#/bin/bash

get_years="http://www.redesparalaciencia.com/programas-2009 http://www.redesparalaciencia.com/programas-de-2008 http://www.redesparalaciencia.com/programas-2010"

for i in $get_years
do
    echo Descargando $i ...
    wget -q -O /tmp/listado_year $i
    echo Descargado
    # Hay algunas URLS que salen con ../
    caps_year=`cat /tmp/listado_year | grep 'href' | grep '>Redes [0-9]' | sed -e 's/\.\.\//http:\/\/www\.redesparalaciencia\.com\//g' -n -e 's/\(.*\)href=\"\([^\"]*\)\"\(.*\)/\2/p'`
#   caps_year=`cat /tmp/listado_year | grep 'href' | grep '>Redes [0-9]' | grep -o '"http://[a-zA-Z0-9.\/\-]*"' | cut -d\" -f2`
    for j in $caps_year
    do
        echo Descargando metadatos del episodio...
        wget -q -O /tmp/episodio $j
        episodio=`grep -o 'http://blip.tv/rss/flash/[0-9]*' /tmp/episodio`
        wget -O /tmp/metadatos $episodio
        echo Metadatos descargados
        video=`awk -F "\"" '/media\:content/ {print $2}' /tmp/metadatos | grep flv`
        titulo=`sed -n 's/<media:title>\(.*\)<\/media:title>/\1/p' /tmp/metadatos`
        if [ -r "$titulo.avi" ] || [ -r "$titulo.flv" ]
            then
            echo "Episodio $titulo ya existe. Descartando."
        else
            echo "Descargando episodio... $titulo"
# Podemos quitar el -q para ver cómo va la descarga.
            wget -q -O "$titulo.flv" $video
            echo "Recomprimiendo episodio..."
            ffmpeg -i "$titulo.flv" -vcodec msmpeg4v2 -b 1200k -acodec mp2 -ab 128k "$titulo.avi"
        fi
    done
done

Requerimientos: wget, sed, awk, ffmpeg (si queréis recomprimir los programas) y algunos gigas libres de disco duro (unos 20 o así si queremos recomprimir).

Notas:

  • La compresión no está muy optimizada, tal vez comprimamos con más bitrate del que debemos, pero bueno. Si no queremos comprimir, basta con comentar la línea de ffmpeg, aunque si queremos verlo en algún reproductor debemos dejarla. El codec de audio (acodec), es mp2, ya que el mp3 no me funcionaba bien, libmp3lame debe estar instalado y ffmpeg compilado con soporte para él, aún así, probad antes).
  • Soy consciente de que hay demasiado sed, awk y scripts de sobra, pero fue un script rápido y tampoco importa mucho el tiempo que pasemos parseando los metadatos.
  • No hay control de errores, si falla algo y el script se vuelve loco… yo no garantizo nada :)
  • Por ahora, si un archivo no se baja del todo, debemos eliminarlo para que se baje de nuevo por completo.

Espero que disfrutéis del programa.

Foto: MikaNet (Flickr)

Búsquedas rápidas en el historial de BASH

Jueves, 6 de Mayo de 2010 admin Sin comentarios

2683642114_bba3d6383e
Cuando pasamos mucho tiempo en escribiendo en terminal, a veces tenemos la necesidad de repetir algo que escribimos en el pasado. Puede que estemos compilando algún programa, o haciendo un ./configure e instalando dependencias de un programa…
Muchas distribuciones lo tienen por defecto (por ejemplo Gentoo), pero otras muchas (Ubuntu, Mandriva, ArchLinux…) no lo tienen; se trata de activar las teclas de Avance y Retroceso de página para hacer búsquedas en nuestro historial.
Esto sirve, por ejemplo para que, si escribimos algunas letras de una orden que enviamos en el pasado, y pulsemos RePag nos encuentre aquellas órdenes que enviamos en el pasado y nos ahorre unas cuantas pulsaciones de teclado.

Lo que debemos hacer es editar el archivo /etc/inputrc, muchas distribuciones traen ciertas líneas parecidas, por lo que si vemos alguna línea que empiece por “\e[5~” o “\e[6~” deberíamos comentarla (con #) o borrarla; y tras ello introducir lo siguiente:

“\e[5~”: history-search-backward
“\e[6~”: history-search-forward

Para mí, es la forma más cómoda de trabajar.

Foto: Liamdunn (Flickr)

Cuando un proceso “se come” la memoria de nuestro sistema

Martes, 20 de Abril de 2010 admin 4 comentarios

pacmanHoy en día no se le suele ver la cara, dado que la memoria de nuestro sistema suele ser grande, pero cuando por ejemplo, a un proceso se le va la mano y reserva más memoria de la que tiene nuestro sistema, entra en marcha un proceso especial del núcleo de Linux; el OOM Killer (Out Of Memory Killer), que se encarga de detectar qué proceso es el peor del sistema y matarlo.
Atendiendo a la documentación (oom_kill.c) tendremos tres opciones cuando nos quedamos sin memoria:

  • Matar un proceso al azar (malo)
  • Congelar el sistema (peor)
  • Matar un proceso de forma inteligente

En fin, si el sistema no está configurado para congelarse (sysctl.kernel_panic_on_oom), intentaremos ver qué proceso tiene más papeletas para morir (el más dañino), y se hace asignando puntuaciones a procesos, en definitiva queremos matar un proceso malo en beneficio para el sistema, no queremos fastidiar diez horas de trabajo frente al ordenador (a menos que sea necesario).

Se sigue el siguiente algoritmo:

  • Los primeros puntos a sumar son la cantidad de memoria del proceso
  • Sumamos la memoria independiente de sus procesos hijos
  • Los procesos con prioridad (nice) duplican la puntuación. Un proceso con nice si se come nuestra memoria compromete el sistema.
  • Los procesos de superusuario dividen por 4 la puntuación. Los procesos de sistema o de superusuario no deberían dar ningún problema, y si root ejecutara algo… él/ella sabe lo que hace ;)
  • Miramos el valor de /proc/ /oom_adj (comprendido entre -17 y +15). Como usuarios, podemos aumentar o disminuir la probabilidad de que un proceso salga elegido para su sacrificio (por el bien del sistema). Si escribimos en ese fichero un -17, nuestro proceso no va a matarlo nunca el OOM killer

Como buen Linux, que nos deja como usuarios poder tocar su funcionamiento, tenemos lo siguiente:

  • /proc/PID/oom_score : Puntuación de un proceso
  • /proc/PID/oom_adj : Asignar o quitar papeletas para que un proceso sea sacrificado (como dije en la lista anterior). Es buena idea que si sabemos que un proceso puede colgar nuestro sistema, le demos un +15; si el sistema se lo carga, mejor; y si es algo importante aunque nuestro sistema ande falto de memoria, le damos un -17
  • sysctl vm.panic_on_oom : En lugar de matar un proceso, lanza un kernel panic.
  • Hay más reglas para configuración si buscamos dentro de sysctl y /proc/

¿Queremos saber qué proceso tiene, ahora mismo, más papeletas para ser sacrificado?
Si disponemos de /proc/sys/vm/oom_victim lo podremos ver ahí, si no, podemos ejecutar este script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
min=0

for pid in `ps axo pid`
do
        if [ -r /proc/$pid/oom_score ]
        then
                puntos=`cat /proc/$pid/oom_score`;
                if (( $puntos > $min ))
                then
                        proceso=$pid;
                        min=$puntos;
                fi
        fi
done

ps ax | grep $proceso

Y lo más importante, queremos lanzarlo a mano, es decir, hay un proceso gastando mucha memoria y procesador, tanta, que no podemos hacer login en el sistema desde consola. Podemos hacer: Alt + SysRq + F y saltará un OMM Manual (Si sysctl kernel.sysrq = 1), es normal que se muera Firefox :) (gasta muchos recursos y Linux lo considera dañino para el sistema)

Foto: Joe Shlabotnik (Flickr)

Visita otras webs de la red

Easy AdSense by Unreal