Sie sind auf Seite 1von 20

TUTORIAL DE SED --------------ndice propuesto: 1. Ha odo hablar de las expresiones regulares? 2. Ejecucin y funcionamiento de sed 2.1.

Qu hace sed 2.2. Sintaxis bsica 2.3. Pattern space y hold space 2.4. Ciclo normal de ejecucin 2.5. Comandos 2.6. Cmo alterar el ciclo de ejecucin 3. Enlaces recomendados 3.1. Expresiones regulares 3.2. sed 4. Guiones comentados 4.1. Guiones en una lnea 4.2. Extraccin de lneas 4.3. Formateo 4.4. Matemticas 4.4. Emulacin de comandos de unix tac wc -l wc -c cat -n/cat -b unix2dos dos2unix Tareas pendientes: a) Escribir la seccin 2.5 1. Ha odo hablar de las expresiones regulares? Sabe usted qu significa /^\(\w\+\) \1$/? Si la respuesta es no, entonces le aconsejo que, antes de seguir leyendo, se instruya en el uso de las expresiones regulares. Yo no las tratar aqu, pero no se apure: hay muchsima informacin disponible en castellano. Consulte la seccin de enlaces, si quiere ahorrarse el trabajo de buscar en google: creo que es suficiente con lo que viene explicado en ellos. 2. Ejecucin y funcionamiento de sed 2.1. Qu hace sed sed es un editor de flujo que toma dos datos de entrada: un flujo de entrada a manipular (p.e. un fichero de texto) y el conjunto de rdenes (guin) que describen la manipulacin. Como flujo de salida devuelve el flujo de entrada modificado segn el guin de rdenes: -- flujo de entrada --, |--> sed ---> flujo de salida modificado ------- guin --------' Si no se especifica el fichero de entrada, sed entiende que se proporcionar a travs de la entrada estndar (teclado). Del mismo modo, si no se direcciona la salida, sed enviar el resultado a la salida estndar (pantalla).

Por ejemplo en: $ sed 's/A-Z/a-z/g' texto.txt tenemos que flujo de entrada: fichero texto.txt guin de rdenes: 's/A-Z/a-z/g', una sola orden en este caso Traducida a romn paladino, la lnea quiere decir: toma el fichero texto.txt (flujo de entrada), convirteme sus letras maysculas en minsculas (guin de rdenes) y mndame (imprmeme) el resultado a la pantalla. 2.2. Sintaxis bsica Existen dos formas de indicar a sed cul es el guin de rdenes: a) En lnea: sed [-e] 'rdenes-del-guin' fichero.txt Indicar el parmetro '-e' es optativo. Al menos en la versin GNU de sed, que es la que yo uso. 'rdenes-del-guin' es una sucesin de rdenes de sed separadas por punto y coma (;). Por ejemplo, sed 'N;P;d' fichero.txt es un guin compuesto por tres rdenes: N, que aade al final del escritorio la siguiente lnea de fichero.txt; P, que imprime la primera lnea del escritorio; y d, que lo borra. El resultado de estas operaciones es un flujo de salida que devuelve las lneas impares del fichero. No se preocupe, si no entiende por qu es as: an no tiene suficientes elementos de juicio. b) Mediante un fichero: sed -f guion.sed fichero.txt En este caso las rdenes de sed estn incluidas en un fichero denominado segn el ejemplo "guion.sed". Es equivalente a usar la forma anterior, aunque esta suele usarse cuando el guin es ms largo y su lectura en una lnea es complicada de entender o escribir. Si se usa el mismo ejemplo anterior, hacer un "cat" de guion.sed devuelve: ### Principio del script ### N # Aade otra lnea al escritorio P # Imprime la primera lnea del escritorio d # Borra escritorio e inicia un nuevo ciclo ### Fin del script ### El uso de la almohadilla (#) para indicar el inicio y el fin del guin y los comentarios no ha sido arbitrario: es el carcter para sealar los comentarios en sed. Si, por alguna razn, se desean escribir en una misma lnea dos rdenes distintas bastar separarlas como en el caso anterior mediante punto y coma (;). Evidentemente, sed admite otros parmetros aparte de -e y -f. Si est interesado en ellos consulte la pgina del manual o el archivo info.

Aparte de estas dos formas bsicas, la shell de bash (lo siento, es la nica que conozco) nos permite hacer una variacin sobre la forma a) (guin en lnea) y una variacin sobre la forma b) (guin en fichero). Tenga claro que estas posibilidades no son exclusivas de sed, sino que son consecuencia de las posibilidades que nos brinda bash. Por tanto, si hablsemos de awk o cualquier otro comando de unix, podramos tambin hablar de ellas. a bis) guin de rdenes en documento interno: sed -f - << "FIN" fichero.txt N P D FIN Es una forma de lograr escribir en lnea el guin con la claridad de separar en distintas lneas las rdenes. Advierta que he incluido el primer FIN entre comillas para evitar que bash realice alguna expansin (a "*","$", etc...) en el guin. Es un mtodo muy til cuando se est escribiendo un guin de bash que incluye una llamada a sed. Si el guin de sed incluido es pequeo, bastar la forma a); pero si es largo y complicado de entender y queremos tener todo reunido dentro del guin de bash, se puede ec mano de este mtodo. Si tiene alguna duda, consulte la seccin Documentos Internos (Here Documents) de la pgina del manual de bash. b bis) Invocacin automtica de sed gracias a la lnea de "shebang": Consiste simplemente en indicarle a bash dentro del propio fichero de guin cul es el programa que debe invocar. En nuestro caso: #!/bin/sed -f P N d Una vez hecho esto, le damos los permisos de ejecucin adecuados al fichero y podremos ejecutarlo directamente: $ ./guion.sed 2.3. Pattern space y hold space sed posee dos buffer en hold space. Yo a partir as) el escritorio y la siquiera una traduccin que representa muy bien los que almacena informacin: el pattern space y el de ahora los llamar (porque me da la gana de hacerlo gaveta: no es una traduccin literal del ingls; ni que haya ledo en algn sitio. Simplemente me parece la funcin de ambos. Si no le gusta, ya sabe:

har

$ sed 's/escritorio/pattern space/g;s/gaveta/hold space/g' tutorial.txt Bueno, bueno... en realidad no lo sabe an, pero espero que acabe sabindolo. ;-) Concretando, como sus nombres indican, el escritorio es el espacio de trabajo

al que se trae el flujo de entrada para manipularlo (borrar, modificar, imprimir, etc...) y la gaveta es un espacio auxiliar en que se pueden meter datos que se prev usar ms adelante sacndolos al escritorio. Esto es importante tenerlo presente, puesto que en sed el trabajo en el escritorio es inmediato, es decir, del flujo de entrada solamente se puede manipular aquello que tenemos en ese preciso momento en l y no lo que ya pas por l o lo que an no ha pasado. 2.4. Ciclo normal de manipulacin sed divide el flujo de datos de entrada en lneas y a cada una de ellas le aplica por separado el guin de rdenes. Por ejemplo, si tenemos un flujo constituido por tres lneas Esta es la primera Esta es la segunda Y esta la ltima sed lo tratar en tres ciclos e ir consecutivamente aplicando el guin a cada una de ellas. Por supuesto, eso significa que en el primer ciclo, tendremos en el escritorio la lnea "Esta es la primera", en el segundo "Esta es la segunda" y en el ltimo "Y esta la ltima". En principio (ya veremos que existen mecanismos para complicar las cosas), si estamos en el segundo ciclo, (es decir, con la lnea "Esta es la segunda" en el escritorio) no podremos volver atrs a hacer algo que dejamos de hacer a la primera lnea "Esta es la primera". Por el mismo principio, no podemos apoyarnos en algo que an este por venir; por ejemplo, nos es imposible saber que estamos en la penltima lnea del fichero, porque sed an no sabe las lneas que quedan por llegar. En general, un ciclo se compone de: 1) Comienzo, en que sed lee la siguiente lnea del flujo de datos y la trae hasta el escritorio para que podamos manipularla. 2) Desarrollo, en que se aplica el guin al contenido del escritorio. 3) Final, en que se manda al flujo de salida lo que quede en el escritorio, se "tira a la basura" su contenido y se vuelve a comenzar un nuevo ciclo en caso de que queden ms lneas por leer. Por supuesto, podemos actuar sobre este ciclo, leyendo lneas antes de comenzar un nuevo ciclo o ingenindonoslas para no tirar a la basura lo que tenemos en nuestro escritorio, etc..., pero antes de hablar de ello es mejor dar un repaso a los comandos. 2.5. Comandos 2.5.1 Lista de comandos [completar] Esto va a ser una traduccin-resumen de lo referente a los comandos y su sintaxis que se puede leer en las pginas info y man). Hasta que tenga tiempo de escribirlo: man sed info sed La segunda de las fuentes es bastante ms prolija. 2.5.2 Ejecucin condicional de comandos

2.5.2.1 Aplicacin del comando a una nica lnea Basta con anteponer el nmero de lnea a la orden. Por ejemplo: sed '2d' fichero.txt Aplica la orden d nicamente a la segunda lnea. El resultado es un flujo de salida con todo el fichero.txt, excepto la segunda lnea. Si quiere verlo, de otro modo, en pseudo-c podramos representarlo como: if (numero_linea == 2) { borra_escritorio(); comienza_ciclo(); } else { /* No se hace nada */ } La ltima lnea del fichero se representa con un dlar ($); pero recuerde, slo sabr que est en la ltima lnea, cuando est en ella. Por tanto, en sed no funcionan cosas como $-1 para representar la penltima lnea. 2.5.2.2 Aplicacin del comando a una lnea que contiene un patrn Se antepone la expresin regular a la orden. Por ejemplo sed '/^ /d' fichero.txt no manda al flujo de salida las lneas que empiezan por un espacio. 2.5.2.3 Aplicacin del comando a un intervalo de lneas Se separa el inicio y el fin del intervalo con una coma y a continuacin se incluye la orden. Tanto el inicio como el fin pueden ser un nmero de lnea o una expresin regular: 1,5d 1,/^$/b /^ /,40d /^A/,/\.$/p 2.5.2.4 Grupos de rdenes Se incluyen entre parntesis ({}): sed '1,5{H;d};$G' fichero.txt Este guin aplica las rdenes H y d a las cinco primeras lneas y la orden G a la ltima. 2.5.2.5 No ejecucin Esto es, ejecuta la orden excepto para tal lnea o tal intervalo: se interpone un cierre de exclamacin (!) entre la lnea/intervalo y la orden. Ejemplos: 2!d /^ /!d 1,5!d ----> Borra la lnea excepto si es la segunda ----> Borra la lnea excepto si empieza con espacio ----> Borra la lnea excepto si est en el intervalo 1-5

1,5!{H;d} ----> Aplica el grupo de rdenes excepto a las lneas 1-5 2.6. Cmo alterar el ciclo de ejecucin Ya se ha explicado cul es el ciclo de ejecucin de sed: traer al escritorio una lnea, cacharrear con ella, imprimirla, tirarla y volver a hacer lo mismo con la siguiente hasta que no queden ms lneas por leer. Sin embargo, este comportamiento normal puede alterarse mediante: 1) Opcin -n: simplemente no imprime el contenido del escritorio al final del ciclo, es decir: $ sed '' fichero.txt imprime todas las lneas del fichero tal cual (ya que no indicamos ninguna orden a sed), pero $ sed -n '' fichero.txt no imprime nada. Digamos que esta opcin nos vuelve mudito a nuestro sed. Si no le indicamos que imprima expresamente algo (p o P), no lo har. 2) Etiquetas, que en combinacin con las rdenes b,t y T, nos permiten avanzar y retroceder a lo largo de las rdenes del guin. Por ejemplo: $ sed ':loop;b loop' fichero.txt Esta ejecucin empezar el primer ciclo (o sea, leer la primera lnea de fichero.txt y la traer al escritorio). A continuacin, se encontrar con un salto incondicional a la etiqueta ":loop", as que saltar hacia adelante; volver a encontrarse con el salto y volver hacia atrs y as ad infinitum... Consecuencia: acabamos de crear un lindo bucle infinito que nos impedir leer alguna vez la segunda lnea. Es ms, como el bucle impide que acabemos el guin de rdenes, ni siquiera llegaremos a imprimir la primera. t y T son etiquetas condicionales. La primera lleva a la etiqueta, si ha logrado hacer alguna sustitucin desde la ltima t o T o bien desde el principio del ciclo. La segunda es una extensin del gnu sed, que hace justamente lo contrario: lleva a la etiqueta si ha fallado alguna sustitucin. se En caso de que no se indique la etiqueta a que hacen referencia b,t o T; entiende que se quiere saltar al final del ciclo.

3) Orden d: Esta orden borra todo el escritorio y comienza un nuevo ciclo de forma normal, aunque an queden rdenes por ejecutarse. 5) Orden D: Borra slo la primera lnea del escritorio. Si el escritorio se queda vaco empieza un ciclo normalmente (lee la siguiente lnea del fichero). Si no est vaco, empieza un ciclo sin leer la siguiente lnea. Por ejemplo: $ sed 'G;D' fichero.txt Este programa se ejecutar eternamente sin que jams se llegue a leer la segunda lnea del fichero. La razn es que G aade al final del escritorio lo que hay en la gaveta (si no se guard previamente nada, una lnea en blanco). Por ello, al ejecutar "D", el escritorio siempre contendr dos lneas, la primera de las cuales ser borrada. Como seguir habiendo una,

no se leer la siguiente lnea de fichero.txt, sino que se seguir trabajando con la lnea que queda. Pero G volver a aadir una segunda lnea, lo que impedir a "D" lograr vaciar completamente el escritorio. Consecuencia: otro lindo bucle infinito. 6) rdenes n/N: nos permiten leer la siguiente lnea sin esperar al fin del ciclo. La primera reemplaza el contenido del escritorio, la segunda aade la nueva lnea al final. 3. Enlaces recomendados 3.1. Expresiones regulares Artculo de LinuxFocus que sirve a modo de introduccin: http://www.linuxfocus.org/Castellano/July1998/article53.html Tutorial bastante extenso en bulma: http://bulma.net/impresion.phtml?nIdNoticia=770 3.2. sed La pgina info de sed (la del manual es bastante escueta): info sed sed trabajando en una sola lnea: recetario de manipulaciones que sed puede hacer con guiones de una sola lnea: http://www.student.northpark.edu/pemente/sed/sed1line.txt Tutorial de sed: sencillamente delicioso. Es el documento con el que he comprendido exactamente cmo funciona sed. Contiene una pequea introduccin a sed con la filosofa de su funcionamiento y la explicacin de sus comandos. Adems incluye multitud de guiones, ms o menos extensos, profusamente comentados. Su didctica es la que pretende imitar este tutorial, que toma de l muchos de los ejemplos. http://www.rtfiber.com.tw/~changyj/sed/ 4. Guiones comentados 4.1. Guiones en una lnea * Mostrar la lnea octava del fichero Borramos cualquier lnea que no sea la octava. Adems tras imprimirla, salimos de sed, puesto que el resto del fichero no nos interesa en absoluto. sed '8!d;q' fichero.txt Obsrvese que no hace falta especificar a qu lnea queremos aplicar q, porque "d" (que se ejecuta para las siete primeras lneas) aborta el resto del guin e inicia un nuevo ciclo. Por supuesto, eliminar q del guin no cambia el flujo de salida. Sin embargo, hace nuestro guin ms rpido, ya que ahorra la ejecucin del ciclo para el intervalo 9,$. * Borrar desde la lnea 3 a la 6 del fichero: Borramos el intervalo de lneas entre la 3 y la 6

sed '3,6d' fichero.txt * Mostrar entre la lnea 3 y la 6 del fichero Borramos cualquier lnea que no se encuentre en ese intervalo. Tras imprimir la sexta salimos, puesto que el resto del fichero no nos interesa en absoluto. sed '3,6!d;6q' fichero.txt En este caso, s es necesario indicar la lnea en que se quiere ejecutar "q", puesto que las lneas 3,4 y 5 no ejecutan d y, por tanto, continan la ejecucin normal del bucle. * Aadir una lnea en blanco despus de cada prrafo. Vamos a considerar que un fin de prrafo se produce cuando hay una lnea que acaba en punto (.). El mtodo es muy simple: cada vez que encontramos una lnea que acaba en punto aadimos al escritorio una lnea en blanco. Para esto, simplemente usamos el comando "G", puesto que si no se ha almacenado nada, la gaveta contiene una lnea vaca. sed '$q;/\.$/G' fichero.txt Otra opcin: sed '$q;s/\.$/.\n/' fichero.txt un En este caso, intentamos sustituir el punto final, por un punto final y retorno de carro (que generar la lnea en blanco). Si no logramos hacer la sustitucin, la lnea de entrada, simplemente, no es alterada. Y el '$q', para qu sirve? Pues, evidentemente, para no aplicar la transformacin a la ltima lnea que, si el texto est bien escrito, acabar con un punto. * Imprimir las lneas impares de un fichero. En este caso el mtodo consiste en leer dos lneas en cada ciclo, pero slo imprimir la primera. sed -n '$!N;P' fichero.txt Como se ha indicado la opcin '-n', no hace falta borrar el escritorio antes de que acabe el ciclo. Otra alternativa es: sed '$!N;s/\n.*$//' fichero.txt En este caso, la manera de evitar que se devuelva la lnea par es hacindola desaparecer mediante una sustitucin. * Imprimir las lneas pares de un fichero. El mtodo equivalente al primero que se sugiri para el ejercicio anterior puede ser:

sed -n '1!{$!N;P}' fichero.txt que es exactamente lo mismo, excepto por el hecho de que en la primera lnea evitamos juntar con la siguiente. Como consecuencia, en el resto de ciclos las parejas de lneas sern 2-3, 4-5, 6-7, etc... Como de cada pareja imprimimos la primera, el resultado es que mostramos las lneas pares. Y el equivalente al segundo: sed '$!N;s/[^\n]*\n\?//' fichero.txt En realidad, este segundo guin tiene un pequeo defecto. Le dejo cmo ejercicio averiguar cul. Se podra corregir as: sed -n '$!N;s/[^\n]*\n//p' fichero.txt 4.2. Extraccin de lneas * Mostrar las seis ltimas lneas de un fichero: Por su forma de trabajar, sed no puede hacer pronsticos sobre cuando acabar el fichero. Por ello, es imposible usar expresiones del tipo $-6 y la nica forma de resolver el problema planteado es mantener en el escritorio las seis ltimas lneas ledas del fichero y, cuando lleguemos a la ltima, imprimir lo que haya en l. Vamos a plantear cuatro posibles soluciones. Por supuesto, todas se basan en la idea que se ha expresado arriba. La utilidad de revisarlas todas es que nos permite razonar sobre la forma en que acta sed. Solucin 1: : loop 1,5 { } $! { } #1 #2 #3 #4 #5 #6 #7 #8 #9

N b loop N D

Las rdenes #1-#5 crean un bucle que nos permite almacenar las seis primeras lneas del fichero en el escritorio. A partir de la sptima lnea, se ejecuta el bloque #6-#9 que va eliminando la primera de las lneas almacenadas en el escritorio (la ms antigua leda) y aadiendo al final la ltima leda. Como consecuencia, cuando leamos la ltima, el escritorio contendr las seis ltimas y no habr que ejecutar ninguna orden, sino procurar que el ciclo acabe normalmente (impresin del escritorio). Solucin 2: Si nos fijamos en el guin anterior, en todos los ciclos se ejecuta una N, as que vamos a dar otra solucin en que la orden N sea comn a los dos bloques: :loop N #1 #2

2,5b loop #3 $!D #4 Sea cual sea la lnea leda, aadimos al escritorio la siguiente (#2). Si hemos ledo alguna de las cinco primeras lneas, volvemos a aadir sin borrar nada (#3). Como consecuencia, la ltima vez que se ejecute #3, acabaremos con las seis primeras lneas del fichero almacenadas en el escritorio. A partir de ese momento, #4 borra la primera lnea e inicia un nuevo ciclo con cinco lneas en el escritorio. Cuando nos encontremos en la lectura de la penltima lnea, N aadir la ltima. Sin embargo, en ella #4 no se ejecutar. Por tanto, acabar el ltimo ciclo de forma normal, esto es, imprimiendo las seis ltimas lneas del fichero. Observe la diferencia de las lneas #2 de la primera solucin y #3 de la segunda: en aquella el intervalo es 1,5 y en la segunda 2,5. La razn est en que en la segunda solucin, antes de expresar el intervalo hacemos "N", as que si estbamos en la lnea 1, leeremos la lnea 2. Solucin 3: :loop $q N 2,6b loop D #1 #2 #3 #4 #5

Muy parecida a la anterior. La nica diferencia es que en este caso la ltima vez que se ejecute N (penltima lnea), tambin se ejecuta D (ltima lnea). Por ello, no debemos almacenar seis lneas consecutivas, sino siete; que sern reducidas a seis cada vez que pasemos por D. Quizs es aconsejable explicar el final del proceso: en el penltimo ciclo nos encontraremos en la penltima lnea, #3 aadir la ltima lnea y #5 borrar la primera de las lneas almacenadas (es decir, la sptima del fichero empezando a contar por el final). El ltimo ciclo, simplemente, ejecuta #2, que imprime el escritorio y sale de sed. Solucin 4: En ella en vez de expresar el primer grupo de lneas, expresamos el segundo. Nos vamos a basar en la solucin 3: :loop $q N 7,$D b loop #1 #2 #3 #4 #5

No es necesario hacer ningn comentario, no? * Borrar las ltimas seis lneas Como sed no sabe lo que an queda por leer del fichero, la nica forma de hacer esto es imprimir con seis lneas de retraso: cuando se va por la lnea 7, imprimir la 1 y, por tanto, cuando se va por la ltima lnea, imprimir la sptima por la cola y salir. As que el problema es muy semejante al anterior: lograr reunir siete lneas en el escritorio y, antes de borrar la primera de ellas, imprimirla

. io

En vez de un $q, se hace un $Q para desechar lo que queda en el escritor (las ltimas seis lneas). Tomemos la ltima de las soluciones del ejemplo anterior: :loop $Q N 7,$ { } b loop #1 #2 #3 #4 #5 #6 #7 #8

P D

Por supuesto, se puede tomar cualquiera. Tomar la penltima nos ahorra los parntesis: :loop $Q N 2,6b loop P D #1 #2 #3 #4 #5 #6

* Devolver toda lnea que contengan /patrn/ y la lnea que inmediatamente preceda a cada una: La forma de razonar es idntica a la de otros guiones: como sed no puede predecir qu contendr la siguiente lnea, es necesario tener dos lneas en el escritorio. /patrn/b $!N /\n.*patrn/!D #1 #2 #3

En caso de que leamos una lnea que contenga "patrn", simplemente la imprimimos y pasamos a la siguiente (#1). Si no lo contiene, ser necesario aadir la siguiente lnea (#2) y comprobar (#3) si est contiene el "patrn". Si no es as, borramos la primera lnea, conservamos la segunda (#3) y comenzamos ciclo con ella; si s, acabamos ciclo normalmente para imprimir las dos lneas. * Devolver toda lnea que contenga /patrn/, las inmediatamente anterior y posterior El algoritmo se basa en acumular lneas en el escritorio (siempre que se haya encontrado una lnea que contenga /patrn/) hasta que la ltima no lo contenga: : loop $!N /patrn/!D /patrn[^\n]*$/!b $!b loop #1 #2 #3 #4 #5

#2 junta la lnea actual con la siguiente. Si en el escritorio no se encuentra /patrn/, #3 borra la primera lnea y regresa a #2 para aadir una nueva. En caso de que s contenga /patrn/, #4 comprueba que la ltima lnea no lo contiene y en tal caso acaba el ciclo normalmente (impresin y

borrado del escritorio). En caso contrario, es necesario seguir aadiendo lneas al escritorio (#5), a menos que se haya llegado al final del fichero. * Borrar todo el contenido comprendido entre /inicio/ y /fin/ Por supuesto, no se supone que ambos patrones se encuentran en una misma lnea, lo que convertira el problema en trivial. En este caso, la forma de actuar es almacenar lneas en el escritorio a partir del momento en que hemos encontrado /inicio/ hasta que hallemos /fin/. /inicio/!b : loop $!N s/inicio.*fin// $!T loop #1 #2 #3 #4 #5

nte

#1 acaba el ciclo normalmente si el escritorio no contiene /inicio/. En caso contrario se entra en un bucle (#2-#5) por el que se van sucesivame aadiendo lneas al escritorio (#3). El bucle acaba, bien porque se ha llegado al final del fichero, bien porque se ha logrado (#5) borrar el contenido entre /inicio/ y /fin/ (#4). En ambos casos se acaba normalmen el ciclo. Ojo! T es una extensin GNU de sed, as que si se usa otro sed es posible que no funcione. No obstante, la misma idea puede plasmarse sin usar T: /inicio/!b : loop $!N s/inicio.*fin// t $!b loop #1 #2 #3 #4 #5 #6

te

Es decir, si la sustitucin tiene xito, acabamos ciclo (#5) saltando #6; si no, regresamos a #3. * Imprimir la ltima lnea de un grupo de lneas consecutivas que contienen todas un mismo campo inicial s Basta con llevar siempre dos lneas en el escritorio y, en caso, de que lo campos iniciales de ambas no coincidan, imprimir la primera. $b N /^\([^ ]* \).*\n\1/!P D #1 #2 #3 #4

#1 acaba ciclo en caso de que estemos en la ltima lnea. En caso contrario, #2 aade la siguiente lnea, #3 imprime la primera lnea en caso de que los campos iniciales sean distintos y #4 la borra y comienza cicl con la segunda lnea.

4.3. Formateo

* Extraer la cabecera de un correo, haciendo que cada campo (From, To, etc...) ocupe una sola lnea A veces es necesario manipular cabeceras de correo. El problema es que es muy comn que las cabeceras ocupen varias lneas; de modo que, si por ejemplo se quieren extraer todos los destinatarios de un mensaje, no basta con manipular la lnea que contiene en patrn /^To: /. Por supuesto, se pueden usar utilidades como formail para remediar este problema, pero vamos a intentar resolverlo todo con sed. La estrategia es aadir lneas al escritorio hasta que nos topemos con un nuevo campo. En ese momento, se imprime el que se ha completado y se comienza a completar el nuevo. /^$/Q : loop N /\n[ \t][^\n]*$/b loop s/\n[ \t]\+/ /g P D #1 #2 #3 #4 #5 #6 #7

El grupo #2-#4 es un bucle que aade lneas al escritorio hasta que sed encuentre una que no empiece por caracteres blancos, seal de que empieza otro campo o se ha llegado al final de la cabecera. Al salir del bucle # elimina todos los cambios de lnea, excepto el ltimo; #6 imprime la primera lnea (el campo completado) y #7 la borra conservando la segunda e iniciando un nuevo ciclo. Si esta segunda lnea es una lnea en blanco (fin de la cabecera), acabamos el proceso (#1). Obsrvese que si lo que se quiere es extraer un campo en concreto, basta con condicionar la orden P. Por ejemplo, /^\(From\|Cc\): /P imprimira los campos de remitente y copia de carbn.

* Separar con una lnea en blanco grupos de lneas consecutivos que contienen todas un mismo campo inicial $q N P /^\([^ ]* \).*\n\1/!i\ D #1 #2 #3 #4 #5

#2 aade la lnea siguiente, #3 imprime la primera lnea del escritorio y, si la segunda lnea empieza con distinto campo, #4 incluye en el flujo de salida una lnea en blanco. En cualquier caso, #5 borra la primera lnea y comienza un nuevo ciclo con la segunda. * Fusionar lneas hasta que haya una que acabe en punto (.): : loop /\.$/b N s/\n/ / $!b loop #1 #2 #3 #4 #5

Si el contenido del escritorio acaba en punto, se acaba el ciclo (#2). S no es as, #3 aade la siguiente lnea y #4 elimina el cambio de lnea. A menos que hayamos llegado al final, #5 vuelve a #2 sin alterar el escritorio.

* Separar prrafos y sangrar (se supone que un prrafo acaba cuando nos encontramos una lnea que acaba en punto) s Como se debe actuar sobre la lnea siguiente a la que contiene un punto, e necesario tener dos lneas en el escritorio: /\.$/!b $q p i\ N s/[^\n]*$/\t&/ D #1 #2 #3 #4 #5 #6 #7

#1 imprime la lnea sin ms en caso de que no se trate un final de prrafo. En caso contrario, #2 comprueba si es la ltima, en cuyo caso la accin se reduce tambin a imprimir. A partir de #2, se ejecuta el algoritmo para incluir una lnea en blanco: #3 imprime, #4 incluye la lnea en blanco, #5 aade la siguiente lnea y #6 le realiza el sangrado. Como remate, #7 borra la primera lnea (que ya se imprimi) y se inicia un nuevo ciclo con la segunda. 4.4. Matemticas * Dado un fichero en que cada lnea es un nmero, sumar una unidad a cada uno de ellos. sed no tiene ningn comando para realizar sumas, de modo que para poder realizar esto, se tiene que estudiar cmo cambia un nmero al que se le suma una unidad y realizar las sustituciones pertinentes. Si le sumamos una unidad: a) Un nmero que est constituido nicamente por nueves, aade una cifra ms a su izquierda: 999 (3 cifras) ---> 1000 (4 cifras). b) Un nmero puede considerarse constituido por una parte variante y una parte invariante. La parte variante est constituida por todos los nueves que hay ms a su derecha y la cifra inmediatamente adyacent izquierda de este grupo de nueves. Por ejemplo, en el caso 1269 1270. La parte variante es 69 y la invariante 12. En el caso par de que no haya nueves, podemos considerar que el grupo de nueves constituido por 0 nueves, de modo que la parte variante es nicame nmero que hay ms a la derecha: 1234 ---> 1235. Parte variante, 5; parte invariante, 123. As pues, si usamos como separador "x" de a parte, algunos ejemplos son:

e a la ---> ticular est nte el mbas

1999 12 1289 999

----> ----> ----> ---->

x1999 1x2 12x89 0999 (aplicando a) primero) ----> x0999

Expresado en la sintaxis de sed la parte variante es /.9*$/. c) Las cifras que varan lo hacen de modo que 0->1, 1->2, ..., 0->9. Expresado en la sintaxis de sed: y/0123456789/1234567890/. Con todo esto ya se puede construir el algoritmo: s/^9*$/0&/ s/.9*$/x&/ h s/*x// y/0123456789/1234567890/ x s/x*// G s/\n// #1 #2 #3 #4 #5 #6 #7 #8 #9

ar

#1 aade un cero delante los nmeros constituidos nicamente por nueves. #2 separa la parte variante de la invariante mediante una "x". Ahora es necesario cambiar la parte variante. Sin embargo, como el comando y es indiscriminado y no se le puede pedir que altere slo a partir de la "x", no nos queda ms remedio que: meter una copia en la gaveta (#3), eliminar la parte invariante (#4), hacer la variacin (#5), intercambiar los contenidos del escritorio y la gaveta (#6), eliminar la parte variante (#7), aadir al escritorio la gaveta (#8) y, dado que la primera lnea contiene la parte invariante y la segunda la variante ya variada, elimin el retorno de carro (#9).

* Trasponer una matriz que viene dada en un fichero de la forma: 11 12 13 21 22 23 31 32 33 Algoritmo: : inicio $! { N #1 #2 #3

b inicio #4 } #5 s/^/\n/ #6 : fila #7 s/$/\a/ #8 : columna #9 s/\n\(\w\+\)[ \t]*\(.*\)$/|\2\1 / #10 t columna #11 y/|/\ / #12 s/^\n*\a// #13 t fin #14 b fila #15 : fin #16

s/ *\a */\n/g

#17

El bucle #1-#6 trae al escritorio todas las lneas del fichero. Una vez qu se tiene toda la matriz, #8 aade al final el carcter "\a" que va a servir para separar la siguiente fila de la matriz traspuesta. El bucle #9-#10 coloca la columna n-sima de elementos tras el ltimo "\a" y separados por espacios. A la vez va sustituyendo los cambios de lnea "\n" por el carcter "|". Cuando ya no queden ms "\n" significar que la columna se ha completado y saldremos del bucle. #12 restituye los "\n" y #13 intenta sustituir una cadena de "\n" desde el inicio del escritorio al primer "\ Si no lo consigue es seal de que quedan ms columnas en la matriz y se ha de comenzar de nuevo (#16). En caso contrario, #15 nos lleva al final #1 en que se sustituyen los "\a" por cambios de lnea El algoritmo tiene una limitacin: no se puede usar "|" en los elementos d la matriz, ya que es usado como carcter de control. Se usa "|" y no cualquier otro carcter de control (por ejemplo, "\r") porque la orden "y" de sed no permite usarlos :(. Se puede estar tentado de usar "s" en vez "y" en #12 para evitar este problema. Sin embargo, esta "s", alterara el funcionamiento de la condicin #14. Lo que s puede hacerse es desplazar la sustitucin hasta despus de #14. Por ejemplo: : inicio $! { N #1 #2 #3

a". 7,

de

----. --'

b inicio #4 } #5 s/^/\n/ #6 : fila #7 s/$/\a/ #8 : columna #9 s/\n\(\w\+\)[ \t]*\(.*\)$/\r\2\1 / #10 t columna #11 s/^\r*\a// #12 t fin #13 <---------------------s/\r/\n/g b fila : fin s/ *\a */\n/g #14 <--- "s" pero despus de #15 #16 #17

* Hacer las sumas en ficheros con formato: num1+num2+num3 num4+num5 num6+num7+num8+num9 . . . Pues s, con un poco de imaginacin, hasta se pueden sumar nmeros! El truco consiste en agrupar las unidades, decenas, centenas, etc... de cad

nmero por lneas, convertir los nmeros en cuentas de un baco, operar con el baco y, al final, traducir el nmero expresado en el baco a base decimal. Por ejemplo, supongamos que recibimos la suma "34+577+1": a) Agrupar unidades, decenas, etc... por lneas: 471 37 5 b) Convertir los nmeros en cuentas de un baco: oooooooooooo oooooooooo ooooo <-- 4+7+1 'o' <-- 3+7 'o' <-- 5 'o'

c) Operar con el baco, es decir, reordenar las cuentas de modo que el baco represente un nmero en base decimal (no puede haber ms de diez cuentas por lnea): oo o oooooo <-- 2 <-- 1 <-- 6

d) Convertir el nmero expresado en el baco en base decimal: 612 Ah va el algoritmo: s/$/+/ : x10 s/$/\n/ : siguiente s/\([0-9]\)\?+\(.*\)$/-\2\1/ t siguiente y/-/+/ s/^+*\n// t numero-abaco b x10 : numero-abaco s/+\n// s/0//g s/1/o/g s/2/oo/g s/3/ooo/g s/4/oooo/g s/5/ooooo/g s/6/oooooo/g s/7/ooooooo/g s/8/oooooooo/g s/9/ooooooooo/g : ordenar s/^\(.*\)o\{10\}\n\?/\1\no/ t ordenar s/$/\n/ : abaco-numero s/^\n\([^0-9]*\)/\10/ s/^o\{1\}\n\([^0-9]*\)/\11/ #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 -+| | | | | Labor a) | | | | -+| | | | | | Labor b) | | | | | -+| Labor c) -+| | | |

s/^o\{2\}\n\([^0-9]*\)/\12/ s/^o\{3\}\n\([^0-9]*\)/\13/ s/^o\{4\}\n\([^0-9]*\)/\14/ s/^o\{5\}\n\([^0-9]*\)/\15/ s/^o\{6\}\n\([^0-9]*\)/\16/ s/^o\{7\}\n\([^0-9]*\)/\17/ s/^o\{8\}\n\([^0-9]*\)/\18/ s/^o\{9\}\n\([^0-9]*\)/\19/ /^[0-9]/!b abaco-numero

#30 #31 #32 #33 #34 #35 #36 #37 #38

| | | Labor d) | | | | | -+-

'

#1-#10 realizan la labor a): #1 aade un signo '+' al final de la lnea, #3 aade una nueva lnea al escritorio, el bucle #4-#6 extrae las cifras que anteceden a los signos '+' y las incluye en la ltima lnea que abrimos con #3. As pues, la primera vez que completemos este bucle la ltima lnea contendr las unidades de todos los nmeros. Como consecuencia del bucle los signos '+' habrn pasado a convertirse a '-'. Para subsanarlo se usa #7. #8 intenta eliminar la primera lnea suponiendo que todo son signos '+ lo que significara que todas las cifras de los nmeros ya han sido agrupadas correctamente y debemos continuar el al algoritmo (#9). Si la sustitucin no ha tenido xito, con #10 volvemos a #3 para aadir una nueva lnea y repetir el proceso. #11-#22 realizan la labor b): cada cifra se sustituye por un nmero de oes igual al nmero que representa (1->'o',2->'oo', etc.). #23-#25 realizan la labor c): encontrar 10 cuentas en una lnea supone sustituirlas por una cuenta en la lnea inmediatamente inferior. El bucle continuar hasta que no queden grupos de 10 cuentas. #26-#38 realizan la labor d): #26 abre una lnea al final del escritorio para ir almacenando el resultado, #28-#37 sustituyen las cuentas por su equivalente en nmero ('' -> 0, 'o' -> 1, etc.). Mientras no queden slo nmeros en el escritorio, #38 nos devuelve al inicio del bucle para seguir convirtiendo cuentas.

4.5. Emulacin de comandos unix * tac (invierte el orden de las lneas de un fichero) 1!G $q h d #1 #2 #3 #4

#1 aade saca el contenido de la gaveta al final del escritorio. Con esto logramos que la nueva lnea est antes que las antiguas. Si hemos llegado a la ltima lnea, acabamos imprimiendo (#2), en caso contrario guardamos el escritorio en la gaveta (#3) y comenzamos ciclo sin imprimir (#4). Si se usa la opcin -n en la invocacin de sed, podramos ahorrarnos una lnea. * wc -l (contar las lneas del fichero) sed -n '$=' fichero.txt * wc -c/wc -w Se propone llevar las cuentas con un baco que almacenamos en la gaveta. Cada vez que leamos una lnea, convertimos todos sus caracteres a cuentas de baco, aadimos una cuenta ms que indica el cambio de lnea "\n" y

reorganizamos las cuentas del baco. Cuando completamos la lectura del fichero, convertimos el nmero almacenado en forma de baco en un nmero en base decimal. s/./o/g s/^/o/ G s/\n// : ordenar s/^\(.*\)o\{10\}\n\?/\1\no/ t ordenar $! { h d } s/$/\n/ : abaco-numero s/^\n\([^0-9]*\)/\10/ s/^o\{1\}\n\([^0-9]*\)/\11/ s/^o\{2\}\n\([^0-9]*\)/\12/ s/^o\{3\}\n\([^0-9]*\)/\13/ s/^o\{4\}\n\([^0-9]*\)/\14/ s/^o\{5\}\n\([^0-9]*\)/\15/ s/^o\{6\}\n\([^0-9]*\)/\16/ s/^o\{7\}\n\([^0-9]*\)/\17/ s/^o\{8\}\n\([^0-9]*\)/\18/ s/^o\{9\}\n\([^0-9]*\)/\19/ /^[0-9]/!b abaco-numero #1 #2 #3 #4 #5 #6 #7 #8 #9 #11 #12 #13 #14 #15 #16 #17 #18 #19 #20 #21 #22 #23 #24

#10

#1 y #2 convierten en cuentas de baco ('o') los caracteres de la lnea. #3 aade al final del escritorio el baco y #4 junta las cuentas correspondientes a la nueva lnea con las cuentas que representan las unidades en el baco. El bucle #4-#6 convierte diez cuentas de un determinado nivel del baco en una sola cuenta en el nivel superior. Si no se ha llegado a la ltima lnea, se guarda el baco en la gaveta y se comienza un nuevo ciclo sin imprimir. Por contra, s ya no quedan ms lneas por leer, #12-#24 convierten el nmero en formato baco en un nmero en base decimal, que se imprimir al acabar el ciclo. Obsrvese que este mismo algoritmo nos sirve para emular wc -w. Basta con sustituir #1 y #2 por una orden que convierta en cuenta cada palabra: s/[^ \t]\+/o/g s/[^o]*//g E, incluso, para contar la presencia de cualquier patrn: s/patrn/\n/g s/[^\n]//g y/\ /o/ * cat -n (listar un fichero anteponiendo a cada lnea su nmero). cat -b Es necesario conservar y presentar el texto de la lnea de modo que no se puede usar '=', porque esta orden manda el nmero de lnea al flujo de salida, no al escritorio. Por ello, es imposible hacer ninguna manipulac para lograr tener en una misma lnea el nmero y el texto.

in

Casi todo este algoritmo se basa en lo realizado para resolver aquel que propona sumar uno a los nmeros que contenan las lneas de un determinado fichero. x s/^9*$/0&/ s/.9*$/x&/ G h s/[0-9]*x\([0-9]*\).*$/\1/ y/0123456789/1234567890/ G s/\n.*\n/ / x s/x.*// G s/\n// h s/ .*$// x #1 #2 #3 #4 #5 #6 #7 #8 #9 #10 #11 #12 #13 #14 #15 #16

rio

#1 trae el nmero de lnea a la gaveta. #2 aade un 0 a los nmeros constituidos exclusivamente por nueves. Obsrvese que cuando la gaveta est vaca, hay un conjunto de 0 nueves y, por tanto, se incluye un 0; de modo que no es necesario tratar de forma particular este caso. #3 separa la parte variante de la invariante. A continuacin, #4 aade la lnea leda al final del escritorio y #5 copia todo en la gaveta. #6 deja en el escrito slo la parte variante. #7 realiza la transformacin de esta parte, #8 y #9 nos permiten incluir la lnea leda despus de la parte variante (la separacin que se ha usado es un espacio). Como an nos falta la parte invariante, #10 intercambia los contenidos de gaveta y escritorio. #11 deja slo la parte invariante y #12 y #13 pegan detrs la parte variante y la lnea. Ya est hecho todo. Sin embargo, hemos de guardar el nmero de lnea en la gaveta para el siguiente ciclo. Por ello, #14 copia el escritorio en la gaveta, #15 elimina el texto de la lnea y, por ltimo, #16 intercambia los contenidos de la gaveta (nmero+texto) y el escritorio (nmero). Si lo que se quiere emular es cat -b, es decir, numerar las lneas excepto las vacas, basta con incluir al principio del guin la orden: /^$/b que evitara la ejecucin del algoritmo, si la lnea leda est vaca.

* unix2dos (eliminar el retorno de carro) sed 's/^M$//' fichero-en-unix.txt > fichero-en-dos.txt ^M Se consigue pulsando Ctrl+V Ctrl+M. * dos2unix (aadir retorno de carro al final de la lnea) sed 's/$/^M/' fichero-en-dos.txt > fichero-en-unix.txt ^M Se consigue pulsando Ctrl+V Ctrl+M.

Das könnte Ihnen auch gefallen