<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>El blog de Deigote &#187; script</title>
	<atom:link href="http://blog.deigote.com/tag/script/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.deigote.com</link>
	<description>El mundo de Deigote. Un diario de cualquier cosa que me resulte interesante (si a alguien más se lo resulta, es otro cantar). Espero que os guste o disguste. Incluso que os deje indiferentes sería una opción tan buena como cualquier otra.</description>
	<lastBuildDate>Thu, 07 Apr 2011 15:29:52 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Mandato PS con salida &#8220;personalizada&#8221;</title>
		<link>http://blog.deigote.com/2010/03/08/custom-output-ps-command/</link>
		<comments>http://blog.deigote.com/2010/03/08/custom-output-ps-command/#comments</comments>
		<pubDate>Mon, 08 Mar 2010 11:56:14 +0000</pubDate>
		<dc:creator>Deigote</dc:creator>
				<category><![CDATA[Informática, internet y tecnología]]></category>
		<category><![CDATA[command]]></category>
		<category><![CDATA[custom]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[output]]></category>
		<category><![CDATA[ps]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://blog.deigote.com/?p=476</guid>
		<description><![CDATA[Cómo definir salida personalizada o custom output para la orden ps en sistemas operativos tipo unix]]></description>
			<content:encoded><![CDATA[<p>Una opción del mandato <a href="http://www.google.es/search?q=ps+linux+command">ps</a> de los sistemas operativos tipo Unix que no suele estar muy bien documentada y que en mi opinión es tremendamente útil es la que permite personalizar la salida del mandato para que muestre la información que te interesa de cada proceso.
</p>
<p>La opción es <em>-o</em>, y acepta como argumentos una gran cantidad de posibilidades, que normalmente se encuentran descritas en la página del manual como <a href="http://ccrma.stanford.edu/planetccrma/man/man1/ps.1.html">standard format specifiers</a> (o directamente no se encuentran <img src='http://blog.deigote.com/wp-includes/images/blank.gif' alt=':D' title=':D' class='wp-smiley smiley-2' /> ).
</p>
<p>Un ejemplo de cómo lucen normalmente las órdenes de tipo <em>ps</em> que suelo lanzar en mis terminales:</p>
<pre><code>$ ps fax -o user,uid,pid,ppid,pgrp,%cpu,%mem,rss,vsize,size,tname,etime,start_time,args
USER       UID   PID  PPID  PGRP %CPU %MEM   RSS    VSZ    SZ TTY          ELAPSED START COMMAND
root         0  3434     1  3434  0.0  0.1   552   5404   464 ?        12-22:14:08 Feb23 /usr/sbin/sshd
root         0 14466  3434 14466  0.0  0.5  2572   8124   512 ?              36:04 12:13  \_ sshd: deigote [priv]
deigote   1000 14469 14466 14466  0.0  0.2  1440   8280   668 ?              36:01 12:13      \_ sshd: deigote@pts/2
deigote   1000 14470 14469 14470  0.0  0.6  3344   6548  2172 pts/2          36:01 12:13          \_ -bash
root         0 16310 14470 16310  0.1  0.2  1196   4292   472 pts/2          00:06 12:49              \_ su -
root         0 16311 16310 16311  0.0  0.3  1688   4740   364 pts/2          00:03 12:49                  \_ -su
root         0 16315 16311 16315  0.0  0.2   992   4148   580 pts/2          00:00 12:50                      \_ ps fax -o user,uid,pid,ppid,pgrp,%cpu,%mem,rss,vsize,size,tname,etime,start_time,args
</code></pre>
<p>Y, de hecho, un par de alias que suelo tener siempre definidos, entre otros, son:</p>
<pre><code>alias ps='ps fax -o user,uid,pid,ppid,pgrp,%cpu,%mem,rss,vsize,size,tname,etime,start_time,args'
alias psg='ps | head -n 1 &#038;&#038; ps | grep'
</code></pre>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.deigote.com/2010/03/08/custom-output-ps-command/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Obtener las extensiones de fichero existentes en un directorio</title>
		<link>http://blog.deigote.com/2010/01/12/obtener-las-extensiones-fichero-existentes-en-un-directorio/</link>
		<comments>http://blog.deigote.com/2010/01/12/obtener-las-extensiones-fichero-existentes-en-un-directorio/#comments</comments>
		<pubDate>Tue, 12 Jan 2010 17:56:40 +0000</pubDate>
		<dc:creator>Deigote</dc:creator>
				<category><![CDATA[Informática, internet y tecnología]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[extension]]></category>
		<category><![CDATA[file]]></category>
		<category><![CDATA[find]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[sed]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://blog.deigote.com/?p=440</guid>
		<description><![CDATA[Cómo obtener la extensión de un fichero, o todas las extensiones que existan a partir de un directorio en bash o sh.]]></description>
			<content:encoded><![CDATA[<p>Una mini-receta rápida para obtener, de forma recursiva, todas las extensiones de fichero que existan a partir de un directorio dado:</p>
<p><code>find directorio_raiz -type f -exec sh -c 'basename $0 | sed "s/.*\.//"' {} \;  | sort | uniq</code></p>
<p>El truco viene del archipoderoso sed, que permite obtener las extensión de un fichero mediante la orden <em>sed &#8220;s/.*\.//&#8221;</em>, y funciona que yo sepa, para cualquier <em>Unix</em> con una shell compatible con <em>sh</em> y <em>find</em>, <em>basename</em> y <em>sed</em> instalados.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.deigote.com/2010/01/12/obtener-las-extensiones-fichero-existentes-en-un-directorio/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Programmed shutdown: pequeño script para apagar la máquina</title>
		<link>http://blog.deigote.com/2009/04/17/programmed-shutdown-pequeno-script-para-apagar-la-maquina/</link>
		<comments>http://blog.deigote.com/2009/04/17/programmed-shutdown-pequeno-script-para-apagar-la-maquina/#comments</comments>
		<pubDate>Fri, 17 Apr 2009 09:09:30 +0000</pubDate>
		<dc:creator>Deigote</dc:creator>
				<category><![CDATA[Informática, internet y tecnología]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[poweroff]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[shutdown]]></category>
		<category><![CDATA[sleep]]></category>
		<category><![CDATA[unix]]></category>
		<category><![CDATA[zenity]]></category>

		<guid isPermaLink="false">http://blog.deigote.com/?p=330</guid>
		<description><![CDATA[Después de buscar (no, mucho, eso si  ) por Google y no encontrar algo que se adaptase a mis mínimas necesidades, me he hecho un pequeño script de apagado de la máquina para mi maravilloso PC en el salón (que no de salón  ) equipado con un GNU/Linux (en concreto una Debian, pero [...]]]></description>
			<content:encoded><![CDATA[<div class="wp-caption alignright" style="width: 260px"><a href="http://deigote.com/img/programmed-shutdown-cropped1.png"><img alt="Programmed shutdown: step 1" src="http://deigote.com/img/programmed-shutdown-cropped1.png" title="Paso 1: ¿cuánto tiempo?" width="250" /></a><p class="wp-caption-text">Paso 1: ¿cuánto tiempo?</p></div>
<p>Después de buscar (no, mucho, eso si <img src='http://blog.deigote.com/wp-includes/images/blank.gif' alt=':D' title=':D' class='wp-smiley smiley-2' /> ) por Google y no encontrar algo que se adaptase a mis mínimas necesidades, me he hecho un pequeño <em>script</em> de apagado de la máquina para mi maravilloso PC en el salón (que no de salón <img src='http://blog.deigote.com/wp-includes/images/blank.gif' alt=':)' title=':)' class='wp-smiley smiley-19' /> ) equipado con un GNU/Linux (en concreto una Debian, pero el script es multiversal dentro del mundo Linux <img src='http://blog.deigote.com/wp-includes/images/blank.gif' alt=':-P' title=':-P' class='wp-smiley smiley-15' /> y quizá Unix, depende de si el software zenity está en otras plataformas o no). </p>
<div class="wp-caption alignleft" style="width: 260px"><a href="http://deigote.com/img/programmed-shutdown-cropped2.png"><img alt="Programmed shutdown: step 2" src="http://deigote.com/img/programmed-shutdown-cropped2.png" title="Paso 2: tú tranqui, que ya te aviso yo..." width="250" /></a><p class="wp-caption-text">Paso 2: tú tranqui, que ya te aviso yo...</p></div>
<p>La idea es poder pedirle a la máquina que se apague dentro de equis minutos, con posilibidad de cancelarlo y cierto feedback visual de cuánto tiempo te queda. Posibles usos son por ejemplo imitar la función Sleep de algunas televisiones, o, cuando te vas de vacaciones y tienes algunas descargas tirando, o algún programa de TV que quieres que se grabe, pedirle que se apague en unos días para no consumir energía tontamente.</p>
<div style="clear:both; height:1em"></div>
<p>El script sólo requiere que esté instalado <a href="http://library.gnome.org/users/zenity/">Zenity</a>. El código fuente del mismo lo podéis ver a continuación:</p>
<pre><code>#!/bin/bash
# Ask for time in minutes to sleep and ater that poweroff the computer
# needs - zenity
# Diego Toharia - deigote@deigote.com

# Messages
TITLE="Apagar el ordenador"
MINUTES_QUESTION="¿Dentro de cuántos minutos?"
WAIT_PRE="Esperando"
WAIT_POST="minutos"

minutes=`zenity --entry --title "$TITLE" --text "$MINUTES_QUESTION" 2>&#038;1` || exit
seconds=`expr $minutes "*" 60`

if [ $seconds != "" ] ; then
	for i in `seq 1 $seconds` ; do
		percentage=`expr $i "*" 100`
		percentage=`expr $percentage "/" $seconds`
		echo $percentage
		sleep 1
	done | zenity --title="$TITLE" --text="$WAIT_PRE $minutes $WAIT_POST" --progress --auto-close --auto-kill
	poweroff
fi</code></pre>
<p>También quiero pensar que, si alguna vez cambio algo, podréis encontrar una versión actualizada en el enlace <a href="http://deigote.com/scripts/x-programmed-shutdown" title="Programmed shutdown">Programmed shutdown script</a> pero no garantizo que  cumpla mis propósitos  <img src='http://blog.deigote.com/wp-includes/images/blank.gif' alt=':-D' title=':-D' class='wp-smiley smiley-2' /> .</p>
<div class="wp-caption aligncenter" style="width: 500px"><a href="http://deigote.com/img/programmed-shutdown-cropped3.png"><img alt="Programmed shutdown: laucher" src="http://deigote.com/img/programmed-shutdown-cropped3.png" title="Lanzador del script" width="490" /></a><p class="wp-caption-text">Programmed shutdown: laucher</p></div>
<p>Para invocarlo, basta guardarlo en un directorio que esté en el <em>path</em> (yo suelo usar para estos scripts $HOME/bin) y darle permisos de ejecución. Recordar que debéis tener permisos para ejecutar el mandato poweoff. En mi caso, tengo en la barra inferior un lanzador precedido del mandato gksudo, de tal manera que el script se lanza con los permisos necesarios, pidiéndome la contraseña en caso necesario.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.deigote.com/2009/04/17/programmed-shutdown-pequeno-script-para-apagar-la-maquina/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Refréscame esa caché</title>
		<link>http://blog.deigote.com/2009/01/02/refrescame-esa-cache/</link>
		<comments>http://blog.deigote.com/2009/01/02/refrescame-esa-cache/#comments</comments>
		<pubDate>Fri, 02 Jan 2009 11:43:25 +0000</pubDate>
		<dc:creator>Deigote</dc:creator>
				<category><![CDATA[Informática, internet y tecnología]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[awk]]></category>
		<category><![CDATA[blog]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[dreamhost]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[lectores]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[servidor web]]></category>
		<category><![CDATA[sitemap]]></category>
		<category><![CDATA[url]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wpcache]]></category>
		<category><![CDATA[wpsupercache]]></category>

		<guid isPermaLink="false">http://blog.deigote.com/?p=289</guid>
		<description><![CDATA[Wordpress, el CMS que uso para gestionar mi blog, dispone de varios plugins para acelerar su carga mediante cachés, algo muy necesario en general, y más si, como yo, eres usuario de un servicio de hosting barato.
En mi caso, el plugin de caché que estoy usando es WPSuperCache, que guarda una copia estática de cada [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://wordpress.org">Wordpress</a>, el <a href="http://es.wikipedia.org/wiki/CMS">CMS</a> que uso para gestionar mi blog, dispone de varios plugins para acelerar su carga mediante <a href="http://es.wikipedia.org/wiki/Cache">cachés</a>, algo muy necesario en general, y más si, como yo, eres usuario de <a href="http://blog.deigote.com/about/#dreamhost">un servicio de hosting barato</a>.</p>
<p>En mi caso, el plugin de caché que estoy usando es <a href="http://wordpress.org/extend/plugins/wp-super-cache/">WPSuperCache</a>, que guarda una copia estática de cada página generada por Wordpress, y la sirve directamente en próximas peticiones, siempre y cuando el usuario no esté registrado. Esto evita todas las peticiones contra la base de datos por parte de Wordpress. Además, opcionalmente, el plugin permite guardar las páginas estáticas con una estructura de directorios equivalente a la URL que las representa, y proporciona <a href="http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html">reescrituras de URL</a> para llegar a dichas páginas directamente, evitando toda intervención por parte de Wordpress (y evitando, por lo tanto, la ejecución de código PHP en el servidor). Finalmente, además, te da la opción de guardar los archivos HTML comprimidos con <a href="http://es.wikipedia.org/wiki/Gzip">GZip</a>. Todas estas opciones aceleran notablemente la carga de la página, puesto que el único trabajo que debe realizarse es el del servidor web: encontrar la página html y servirla.</p>
<p><a href="http://wordpress.org/extend/plugins/wp-super-cache/">WPSuperCache</a>, como la mayoría de plugins de caché, cuenta con un borrado automático de la caché cada cierto tiempo. Cada vez que se ejecuta esta tarea, las siguientes peticiones (si las hay <img src='http://blog.deigote.com/wp-includes/images/blank.gif' alt=':-D' title=':-D' class='wp-smiley smiley-2' /> ) a las distintas páginas del blog harán que se regenere la caché automáticamente.</p>
<p>Sin embargo, cuando tienes pocas visitas, no es buena idea hacer que la caché sea regenerada por los lectores. En ese caso, el mío <img src='http://blog.deigote.com/wp-includes/images/blank.gif' alt=':-)' title=':-)' class='wp-smiley smiley-19' /> , es probable que un lector obtenga una página no cacheada en vez de una que sí lo está. Una posiblidad es aumentar en gran medida el intervalo de borrado de la caché, pero en general es preferible tener una caché actualizada. La otra posiblidad es, además de borrar la caché, regenerarla automáticamente, de tal manera que todos los lectores del blog se beneficien de la caché del mismo.</p>
<p>En mi caso, he escrito un script que visita todos los enlaces de una página web basándose en el <a href="http://es.wikipedia.org/wiki/Site_map">sitemap</a> de la misma, siempre que este cumpla el <a href="http://www.sitemaps.org/protocol.php">protocolo descrito por Sitemaps.org</a>. El código es el siguiente:</p>
<pre><code>#!/bin/bash
# Visit all the links provided by a sitemap file.
# Diego Toharia - http://blog.deigote.com

# Verify parameter
if [[ $# -ne 1 ]] ; then
    echo "Error: first parameter (sitemap URL) missing"
    echo "Usage: `basename $0` "
    exit 1
fi

url=$1
links=`wget -q -O - http://blog.deigote.com/sitemap.xml | awk '{ print $1 }' | grep "^http" | awk 'BEGIN { FS="&gt;" } { print $2 }' | awk 'BEGIN { FS="&lt;" } { print $1 }'`

for i in $links ; do
	echo "Visiting " $i
	wget -q -O - $i &gt; /dev/null
done
</code></pre>
<p>Seguro que hay formas más elegantes de hacerlo, pero awk es tan potente que es difícil resistirse a usarlo <img src='http://blog.deigote.com/wp-includes/images/blank.gif' alt=':-D' title=':-D' class='wp-smiley smiley-2' /> . Lo he llamado <a href="http://deigote.com/scripts/visit_site_by_sitemap">visit_site_by_sitemap</a>, original que es uno <img src='http://blog.deigote.com/wp-includes/images/blank.gif' alt=':roll:' title=':roll:' class='wp-smiley smiley-17' /> .</p>
<p>Una vez tenemos el script, lo más fácil es programar una tarea del cron que cada cierto tiempo (preferiblemente, en franjas horarias con el menor tráfico posible) borre la caché y ejecute el script pasándole como parámetro la URL del sitemap. Por cierto que, en mi caso, el sitemap lo genera el plugin <a href="http://wordpress.org/extend/plugins/google-sitemap-generator/">Google Sitemap Generator</a>. El mandato para la regla en mi caso sería algo como:</p>
<pre><code>cd path/al/blog/wp-content ; find cache -type f -name '*.html' -exec rm {} \; -o -name '*.gz' -exec rm {} \; ; ~/bin/visit_site_by_sitemap http://blog.deigote.com/sitemap.xml
</code></pre>
<p>La idea es borrar todos los ficheros html y gz generados por la caché y regenerar la misma visitando todos los enlaces proporcionados por el sitemap del blog.</p>
<p>Podemos hacer un par de pruebas que, sin ser demasiado científicas, nos dan una idea del beneficio que obtenemos. La primera sería ejecutar en local el script dos veces, previo borrado de la caché. La primera visitaría todos los enlaces sin disponer de caché, mientras que la segunda lo haría usando la caché.</p>
<pre><code>$ cd path/al/blog/wp-content
$ find cache -type f -name '*.html' -exec rm {} \; -o -name '*.gz' -exec rm {} \;
$ time ~/bin/visit_site_by_sitemap http://blog.deigote.com/sitemap.xml
Visiting  http://blog.deigote.com/
...
real    4m12.102s
$ time ~/bin/visit_site_by_sitemap http://blog.deigote.com/sitemap.xml
Visiting  http://blog.deigote.com/
...
real	0m7.759s
</code></pre>
<p>Podemos ver que los resultados son espectaculares. De 4 minutos hemos pasado a 7 segundos. Sin embargo, estamos probando el caso óptimo, en el que la latencia es mínima y la velocidad de conexión con el servidor web es máxima, lo que hacen que la capacidad de proceso sea el único parámetro que influye en los resultados.</p>
<p>Si ejecutamos esta misma prueba en una máquina externa y situada en España, la misma desde la que estoy escribiendo, obtenemos unos resultados bien distintos: casi trece minutos (12m45) frente a casi 9 (8m44s).</p>
<p>Sin embargo, esto es culpa de la lamentable latencia y velocidad de conexión que Dreamhost tiene en España, ya que ejecutando la prueba en una máquina situada en USA (y de otro servicio de hosting distinto), se obtienen 3 minutos (3m02s) frente a 22 segundos, resultados más parecidos a la ejecución en local. Tendré que pensar seriamente en cambiar de hosting <img src='http://blog.deigote.com/wp-includes/images/blank.gif' alt=':cry:' title=':cry:' class='wp-smiley smiley-5' /> .</p>
<p>La otra prueba que se puede hacer es algo más realista: medir el tiempo de descarga de una única página, que es lo que hace un usuario cualquiera (no creo que tenga ningún lector tan fan como para visitarse todas las entradas del blog una detrás de otra <img src='http://blog.deigote.com/wp-includes/images/blank.gif' alt=':lol:' title=':lol:' class='wp-smiley smiley-10' /> ). En mi caso, he usado un navegador <a href="http://www.mozilla-europe.org/es/firefox/">Firefox</a> con la caché deshabilitada y con la extensión <a href="https://addons.mozilla.org/es-ES/firefox/addon/1843">Firebug</a> instalada, usando la pestaña Red de dicha extensión para medir el tiempo de carga del HTML de la página de inicio. He realizado varias pruebas con la caché vacía y con la caché llena y he obtenido de media unos 2.5 segundos frente a medio segundo respectivamente, lo cual no está mal. Sin embargo, el resto de elementos de la página (malditos emoticonos <img src='http://blog.deigote.com/wp-includes/images/blank.gif' alt=':evil:' title=':evil:' class='wp-smiley smiley-7' /> ) ralentiza la carga total de la misma en gran medida, aunque eso es otra historia <img src='http://blog.deigote.com/wp-includes/images/blank.gif' alt=':-)' title=':-)' class='wp-smiley smiley-19' /> .</p>
<p>Gracias a Álvaro por su inestimable ayuda a la hora de lanzar el <em>juego de pruebas</em> <img src='http://blog.deigote.com/wp-includes/images/blank.gif' alt=':P' title=':P' class='wp-smiley smiley-15' /> en un servidor externo a españa.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.deigote.com/2009/01/02/refrescame-esa-cache/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Bucles en la terminal</title>
		<link>http://blog.deigote.com/2006/09/22/bucles-en-la-terminal/</link>
		<comments>http://blog.deigote.com/2006/09/22/bucles-en-la-terminal/#comments</comments>
		<pubDate>Fri, 22 Sep 2006 08:07:28 +0000</pubDate>
		<dc:creator>Deigote</dc:creator>
				<category><![CDATA[Informática, internet y tecnología]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[bucles]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[tcsh]]></category>
		<category><![CDATA[terminal]]></category>

		<guid isPermaLink="false">http://www.deigote.com/blog/2006/09/22/bucles-en-la-terminal/</guid>
		<description><![CDATA[Hace poco necesitaba yo borrar, en una estructura de directorios, todos los ficheros cuya extensión fuera .class. Estas tareas suelen ser un tedio, pero muy fáciles de solucionar si sabes un poco de shell scripting. El ejemplo es el siguiente:

 $ for i in `find . -name '*.class'` ; do echo "Borrando $i" ; rm [...]]]></description>
			<content:encoded><![CDATA[<p>Hace poco necesitaba yo borrar, en una estructura de directorios, todos los ficheros cuya extensión fuera <em>.class</em>. Estas tareas suelen ser un tedio, pero muy fáciles de solucionar si sabes un poco de <em>shell scripting</em>. El ejemplo es el siguiente:<br />
<br />
<code> $ for i in `find . -name '*.class'` ; do echo "Borrando $i" ; rm "$i" ; done </code><br />
Esto haría la magia en una terminal con intérprete de mandatos <em>bash</em>. Si usais <em>tcsh</em> como yo, la cosa es un poco distinta:<br />
<br />
<code> $ foreach i ( ` find . -name '*.class' ` )<br />
foreach? echo "Borrando $i"<br />
foreach? rm $i<br />
foreach?end<br />
</code><br />
Como se ve, en <em>tcsh</em> es un poco menos intuitivo, ya se sabe que para programar, <em>bash</em> es bastante mejor :-), pero el resultado es equivalente.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.deigote.com/2006/09/22/bucles-en-la-terminal/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Mini tutorial de awk</title>
		<link>http://blog.deigote.com/2006/08/30/mini-tutorial-de-awk/</link>
		<comments>http://blog.deigote.com/2006/08/30/mini-tutorial-de-awk/#comments</comments>
		<pubDate>Wed, 30 Aug 2006 10:02:02 +0000</pubDate>
		<dc:creator>Deigote</dc:creator>
				<category><![CDATA[Informática, internet y tecnología]]></category>
		<category><![CDATA[awk]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://www.deigote.com/blog/2006/08/30/mini-tutorial-de-awk/</guid>
		<description><![CDATA[Por petición popular, voy a escribir un poco sobre un mandato típico de los sistemas operativos UNIX (apareció por primera vez en 1977 nada menos), awk.
awk es un mandato que sirve para procesar líneas de texto (separadas, naturalmente, por un salto de línea). awk cuenta con un pequeño y sencillo lenguaje de programación que es [...]]]></description>
			<content:encoded><![CDATA[<p>Por <a href="http://www.deigote.com/blog/2006/08/17/dando-capacidades-multimedia-a-ubuntu-dapper-con-easyubuntu/#comment-51">petición popular</a>, voy a escribir un poco sobre un mandato típico de los sistemas operativos UNIX (apareció por primera vez en 1977 nada menos), <a title="AWK programming language" href="http://en.wikipedia.org/wiki/AWK_programming_language">awk</a>.</p>
<p>awk es un mandato que sirve para procesar líneas de texto (separadas, naturalmente, por un salto de línea). awk cuenta con un pequeño y sencillo lenguaje de programación que es interpretado (no necesita ser compilado), y resulta tremendamente útil cuando queremos extraer información de extensos campos de texto (y, posiblemente, manipularla).</p>
<p>El funcionamiento del madato awk es muy sencillo: basicamente tenemos dos posiblidades:</p>
<p><code> $ awk -f <em>fuente.awk</em> <em>fichero_entrada.txt</em></code><br />
<code> $ awk '<em>fragmento de código fuente</em>' <em>fichero_entrada.txt</em></code></p>
<p>En la primera de ellas, el código fuente está en un fichero (recomendado para usos que vayan a repetirse con el tiempo y con códigos fuentes largos) mientras que el segundo ofrece la ventaja de poder poner el código fuente como un argumento más. Esto es muy útil para el uso de awk en <em>scripts</em> o similares, en los que el uso de ficheros puede ser un engorro. También cabe la posibilidad de omitir el fichero de entrada, en cuyo caso awk leerá de la entrada estándar.</p>
<p>Respecto al lenguaje awk, tiene una estructura similar a lo siguiente:</p>
<p><code>BEGIN { <em>acción</em> }<br />
/<em>patrón</em>/ { <em>acción</em> }<br />
END { <em>acción</em> }</code></p>
<p>La forma de funcionamiento la siguiente:</p>
<ol>
<li>Nada más comenzar la ejecución, se evaluará la acción marcada entre llaves precedida por la palabra reservada <em>BEGIN</em>.</li>
<li>Por cada campo de texto (recordemos, por defecto líneas) awk evaluará si se ajusta al patrón (una <a href="http://es.wikipedia.org/wiki/Expresi%C3%B3n_regular">expresión regular</a>), y de ser así, ejecutará la acción marcada entre llaves que sigue a dicho patrón. Por cada líneas se evaluarán todos los patrones a menos que en una de las acciones ejecutadas se encuentre la orden <em>next</em>, en cuyo caso se comenzará desde el principio con la siguiente línea.</li>
<li>Finalmente, se procesará la acción marcada entre llaves precedida por la palabra reservada <em>END</em>.</li>
</ol>
<p>Respecto a los <strong>patrones</strong> de awk, son, como ya he dicho, expresiones regulares. No voy a explicar aquí todas las posiblidades porque no acabaría nunca (y con la <a title="Las expresiones regulares en programación" href="http://es.wikipedia.org/wiki/Expresi%C3%B3n_regular#Las_expresiones_regulares_en_programaci.C3.B3n">ayuda de la Wikipedia</a> os debería bastar), basten un par de ejemplos:</p>
<ul>
<li>/[afP]MEMOLO[1-3]z/ casará con cualquier línea que contenga las letras a, f o P seguidas de la cadena MEMOLO seguidas de un dígito comprendido del 1 al 3 y seguida por la letra z.</li>
<li>/[afP](MEMOLO)+([1-3])*z/ casará con cualquier línea que contenga las letras a, f o P seguidas de la cadena MEMOLO una o varias veces seguidas de un dígito comprendido del 1 al 3 que puede aparecer ninguna, una, o varias veces y seguida por la letra z.</li>
</ul>
<p>Esta es la parte más complicada de awk (ya sabeis lo que <a title="Jamie Zawinski dijo" href="http://www.deigote.com/blog/2006/08/21/jamie-zawinski-dijo/">se dice de las expresiones regulares</a>).</p>
<p>En cuanto a las <strong>acciones</strong>, cualquiera que haya programado en C no tendrá mucho problema, ya que es similar. Como características cabría destacar:</p>
<ul>
<li>El acceso a las línea actual se hace mediante unas variables especiales. En concreto $0 referencia a toda la línea mientras que $1, $2, etcétera, referencian a los campos de dicha línea. El separador de campos por defecto es un espacio o un tabulador, pudiéndose modificar en la acción de <em>BEGIN</em> con la variable FS (otra expresión regular, por cierto).</li>
<li>No es necesario declarar ni tipar las variables, cuyo formato es el mismo que en C (su expresión regular, para que vayais practicando, es algo parecido a <em>[a-Z]([a-Z] | [1-9] | _ )*</em>).</li>
<li>Están permitidas todas las estructuras clásicas de programación en un formato estilo C (bucles, expresiones condicionales, operadores, etcétera).</li>
<li>Para imprimir resultados, existen dos posiblidades. La primera, <em>print</em>, es la más cómoda, puesto que no es necesario usar paréntesis para sus argumentos y cuenta con concatenación automática de los mismos (algo parecido al mandato <em>echo</em> de la terminal. Por ejemplo, <em>print &#8220;la línea &#8221; $0 &#8220;tiene &#8221; NF &#8221; palabras&#8221;</em> imprimirá la frase que precede a <em>print</em> sustituyedo $0 por la línea actual y NF (otra variable especial) por el número de campos de la misma. Como segunda posibilidad, tenemos <em>printf</em>, que ofrece mayor control (es idéntico al del lenguaje C).</li>
</ul>
<p>¿Y qué pasa con los los jugosos <strong>ejemplos</strong>? Pues he recopilado alguno que otro según me ha ido surgiendo la necesidad de usarlo estos días.</p>
<ul>
<li>Por ejemplo, el otro día necesitaba obtener del fichero de <em>log</em> de Tomcat las líneas que contuviesen o bien &#8220;SOAP21&#8243; o bien &#8221; &#8211; 2 &#8220;. Esto sería sencillo de hacer con dos grep, pero yo necesitaba que esas líneas mantuviesen el orden en el que habían aparecido en el fichero, y hacer eso con un grep requiere de una expresión regular bastante más compleja de lo que en realidad es necesario. Además, quería saber en qué número de línea del fichero estaba cada línea buscada. Con awk, fue tan sencillo como esto:<br />
<code> cat tomcat.log | awk '/SOAP21/{print NR " - " $0} / - 2/{print NR " - "$0}'</code></li>
<li>También necesité, en el mismo fichero, verificar que se cumpliese una secuencia, y concretamente, me valía saber que, dentro del conjunto de líneas que contenían &#8220;SOAP21&#8243;, las múltiplo de 5 eran idénticas, ya que de esta manera sabía que se habían cumplido todos los pasos. Por lo tanto, necesitaba sacar las líneas que tuviesen &#8220;SOAP21&#8243;, y dentro de éstas, sólo las que su número de línea fuese múltiplo de 5. Nuevamente, awk te lo pone fácil:<br />
<code> cat tomcat.log | awk 'BEGIN { nl = 1 } /SOAP21/ { if (nl % 5 == 0) print ; nl++}'</code></li>
<li>En plan más &#8220;complicado&#8221; (teniendo en cuenta que lo de antes era trivial), hice una pequeña línea para sacar la nota media a partir del archivo html que te devuelve <a title="Universidad Politécnica de Madrid. Consulta de expedientes" href="https://www.upm.es/expedientes/">la UPM</a> cuando consultas tu expendiente usando la modalidad &#8220;Último estado de cada asignatura&#8221; (aunque falla cuando tienes alguna matrícula, pero bueno, eso no es lo importante ahora). El código es el siguiente:<br />
<code>cat consulta.upm.html | grep "<br />
/&lt;\/table&gt;/ { d = 0 } { if (d &gt; 0) { if (c == 10) { print ; c = 0 } else c++ } }' | grep<br />
'&gt;\([1-9][0-9]\|[1-9]\|[1-9]\,[0-9]\{1\}\|[1-9]\,[0-9]\{2\}\)&lt;' | cut -d 1 -f2 -d'&gt;' | cut<br />
-f1 -d'&lt;' | awk 'BEGIN { t=0.0;n=0; } {print ; t=t+$1 ; n++} END { print "Total " t "<br />
Asignaturas " n " Media " t/n}'</code><br />
Como veis, el primer fragmento de awk hace una selección de líneas, imprimiendo sólo las filas de las tablas que sean múltiplo de 10 (son en las que se encuentran las notas) y que estén contenidas entre una línea que tenga la palabra Obs y el primer final de tabla en html. Una vez obtenidas estas líneas, uso grep para quedarme solo con las que tienen nota y cut para dejar sólo la nota, quitando el resto de elementos html. El segundo fragmento de awk se encarga de ir sumando las notas y el número de asignaturas para imprimir la media.</li>
<p><strong>EDITO:</strong> iré añadiendo más fantabulosos ejemplos <img src='http://blog.deigote.com/wp-includes/images/blank.gif' alt=';-)' title=';-)' class='wp-smiley smiley-22' /> según me los vaya encontrado.</p>
<li><a title="Pablo Toharia @ dac" href="http://www.gmrv.es/~ptoharia/">Mi hermano</a> el otro día me preguntó como resolvería un problema y le sugerí que usara awk. El problema consistía en que tenía ficheros (por cierto, de más de 80.000 líneas) con una estructura tal que<br />
<code>frase1 1<br />
frase2 5<br />
...<br />
fraseN M</code><br />
y quería sumar los números de cada frase. En el caso original tenía la ventaja de que las frases siempre iban en el mismo orden en todos los ficheros, pero la sencillez de awk hace que la solución (que corre a cargo de mi hermano, por cierto) valga para casos que no estén en orden (e incluso que aparezcan frases en algunos ficheros y en otros no). Además, se requería que fuese relativamente rápido, y awk cumplió con las expectativas (la solución previa eran pruebas con <em>scripts</em> más o menos a mano y los resultados se iban por encima de los 10 minutos, frente a los 2 minutos de la solución con awk). El único problema era juntar la salida de los ficheros, pero awk permite trabajar con varios ficheros de entrada de datos (si no, un poquito de <em>bash scripting</em>, for i in *.out ; do cat $i ; done, lo hubiese solucionado). Los ficheros tenían extensión .out, por lo que la solución final es:<br />
<code>awk 'BEGIN { FS = " ";} { resultados[$1] += $2 } END { for(category in resultados) print category, resultados[category]; } *.out'</code><br />
Como veis es sencillo, limpio y eficaz <img src='http://blog.deigote.com/wp-includes/images/blank.gif' alt=':-D' title=':-D' class='wp-smiley smiley-2' /> ¡con awk, la suciedad se va en un bang! Aquí además podeis ver algunas cosas más de awk, como los bucles, los <em>array</em> (estilo PHP, sin declaración ni reserva de memoria ni inicialización de datos) y la variable especial <acronym title="Field separator">FS</acronym>, que sirve para especificar cómo separar los campos de una línea (aunque en este caso no haga falta porque por defecto es espacio o tabulador).</li>
</ul>
<p>Y esto es todo por hoy. Huelga decir que en Internet encontrareis cientos de ejemplos y tutoriales, pero yo quería hacer una pequeña introducción con un par de ejemplos más prácticos que los que suelo encontrar (al menos, serían prácticos para mí ;-)). Espero que os sea de utilidad.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.deigote.com/2006/08/30/mini-tutorial-de-awk/feed/</wfw:commentRss>
		<slash:comments>26</slash:comments>
		</item>
		<item>
		<title>Any to mp3</title>
		<link>http://blog.deigote.com/2005/09/06/any-to-mp3/</link>
		<comments>http://blog.deigote.com/2005/09/06/any-to-mp3/#comments</comments>
		<pubDate>Wed, 07 Sep 2005 00:37:00 +0000</pubDate>
		<dc:creator>Deigote</dc:creator>
				<category><![CDATA[Informática, internet y tecnología]]></category>
		<category><![CDATA[any2mp3]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[for]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mp3]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[terminal]]></category>
		<category><![CDATA[wma]]></category>

		<guid isPermaLink="false">http://www.deigote.com/blog/?p=4</guid>
		<description><![CDATA[Un script que convierte cualquier archivo (wav, wma, avi, etc) a mp3]]></description>
			<content:encoded><![CDATA[<p>¡Bueno, pues aquí va la primera entrada :D! ¿Nunca os las habeis visto con los malditos archivos wma? Yo si, y debo decir que son odiosos, nada menos que de <a href="http://www.microsoft.com">Mocosoft</a>. Más que nada, no me gustan porque mi fabulosa radio no lee más que MP3. Asín que, con las mismas, he hecho un cutre script que convierte cualquier archivo de cualquier tipo que pueda leer mplayer (es decir, cualquiera :)) a formato mp3. Incluso se puede usar para extraer el sonido de un archivo de video cualquiera (un concierto, por ejemplo :)). Aquí os dejo el estupendo y citado script:</p>
<pre><code>
#!/bin/bash
# any2mp3 - Recives an extension and convert any file with this extension
#           to mp3 using mplayer and lame.
# Requirements - mplayer, lame.
# Diego Toharia - deigote@gmail.com

# Verify parameter
if [[ $# -ne 1 ]]
then
  echo "Error: first parameter (file extension to convert) missing"
  echo "Usage: `basename $0` "
  exit 1
fi
ext=$1

# Remove spaces
for i in *.$ext; do
  mv "$i" `echo $i | tr ' ' '_'` ;
done

# To wav with mplayer, to mp3 with lame.
for i in *.$ext ; do
  name="`basename "$i" ."$ext" | tr '_' ' '`.mp3"
  echo $name
  mplayer $i -ao pcm:file=scratch.$$.wav &amp;&amp; \  lame -h -V 7 scratch.$$.wav "$name" ;
done

# Remove scratch file
rm scratch.$$.wav
</code></pre>
<p>Por supuesto, sólo para <a href="http://www.linux.org">Linux</a>. ¿O que pensabais?</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.deigote.com/2005/09/06/any-to-mp3/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
<!-- WP Super Cache is installed but broken. The path to wp-cache-phase1.php in wp-content/advanced-cache.php must be fixed! -->
