Sed en una-línea (sed one-liners) Parte I

Sed en una-línea, Parte I

Famous Sed One-Liners Explained, Part I

Dado que no hay muy buena documentación en español acerca del comando sed, me decidí a traducir una serie de excelentes artículos creados por Peteris Krumin. Le he pedido permiso expreso a su autor y no tuvo inconvenientes, así que aquí va.

Nota del Traductor (NdT): No será una traducción total, dado que hay mucha información anecdótica y sólo me limitaré a la explicación del comando sed.

Aquí comienza la traducción:

Estos “one-liners” (sed en una-línea) fueron compilados por Eric Pement y los puedes descargar desde aquí.

La mayoría de las personas están familiarizados con un comando de sed en particular: “s” de substituir. s/command/command/. Esto no es del todo satisfactorio. Sed tiene al menos 20 comandos diferentes. Incluso se puede escribir el tetris en él, tal y como hizo Julia Jomantaite.

Los one-liners de Eric están divididos en varias secciones:

  1. Espaciado de un archivo (explicado aquí)
  2. Numeración (explicado aquí)
  3. Conversión y sustitución de texto (explicado aquí)
  4. Impresión selectiva de ciertas líneas (explicado en parte II)
  5. Eliminación selectiva de ciertas líneas (explicado en parte III)
  6. Aplicaciones especiales (explicado en parte III)

Antes de comenzar quisiera compartir la idea clave que cambió mi forma de pensar en sed. Fueron los cuatro espacios de sed: input stream, output stream, pattern space y hold buffer. Sed trabaja en el input stream (flujo de entrada) y produce un output stream (flujo de salida). Las líneas del flujo de entrada son colocadas en el pattern space (espacio de patrón) donde son modificadas. El hold buffer (buffer de almacenado) puede ser utilizado como un almacenamiento temporario.

Ahora si, toma una copia de mi cheat sheet, imprímela y metámonos en los one-liners.

Espaciado de un archivo

1 Espaciado doble en un archivo

sed G

Este sed de una sola línea utiliza el comando ‘G’. Si tomó la cheat sheet verá que el comando ‘G’ agrega en el pattern space una nueva línea seguida por el contenido del hold buffer. En este ejemplo, el buffer se encuentra vacío (sólo tres comandos ‘h’, ‘H’ y ‘x’ pueden modificar el buffer), por lo que se termina simplemente añadiendo una nueva línea en el pattern space. Una vez que todos los comandos se han procesado (en este caso, sólo la ‘G’ comando), sed pone el contenido del pattern space en el output stream (flujo de salida) seguido de una nueva línea. Allí lo tenemos, dos saltos de línea – uno añadido por comando ‘G’ y otro por la salida. El archivo ha sido doble-espaciado.

2 Espaciado doble en un archivo que contiene líneas en blanco. Lo haremos de manera que la salida no contenga más de una linea en blanco entre dos líneas de texto.

sed '/^$/d;G'

Esta línea sólo opera en las líneas que coinciden con una expresión regular /^$/. ¿Cuáles son esas líneas? Son líneas vacías. Tenga en cuenta que antes de hacer que la expresión regular coincida, sed empuja el input stream al pattern space. Al hacerlo, sed descarta el último carácter (que es nueva línea). Las líneas en blanco contienen solo el carácter de nueva línea, de modo que después de haber sido puestas en el pattern space, este carácter se elimina y el pattern space permanece vacío. La expresión regular /^$/ coincide con el pattern space vacío y se aplica el comando ‘d’ que suprime el actual pattern space, lee la siguiente línea, lo pone en el pattern space y aborta el actual comando, y se inicia la ejecución desde el principio. Las líneas que no coinciden con el vacío obtendrán una nueva línea por el comando ‘G’, al igual que en 1.1.

En general, sed permite restringir las operaciones a algunas líneas (5, 27, etc), a una serie de líneas (líneas 10-20), a líneas que se correspondan a un patrón (por ejemplo las líneas que contengan la palabra “catonmat”), y en líneas entre dos patrones (por ejemplo entre “catonmat” y “coders”).

3. Triple-espaciado en un archivo.

sed 'G;G'

Los comandos se puede combinar en una misma línea, utilizando punto y coma ; . Estos comandos serán ejecutados uno tras otro. Este one-liner realiza dos veces lo que el primero (en 1.1), agrega dos nuevas líneas a la salida.

4. Deshacer espaciado doble

sed 'n;d'

Este one-liner asume que incluso las líneas en blanco estarán numeradas. Utiliza dos nuevos comandos ‘n’ y ‘d’. El comando ‘n’ imprime el pattern space actual (a menos que el parámetro -n haya sido especificado), vacía el pattern space actual y lee la siguiente línea entrada. Aquí vemos que ‘n’ imprime la primera, tercera, quinta, … línea y lee la siguiente. La línea siguiente a la que se ha impreso es siempre una línea vacía. Ahora el comando ‘d’ se ejecuta. Este comando borra el patter space actual, lee la siguiente línea, pone la nueva línea en el pattern space, aborta el comando actual y reinicia la ejecución del primer comando pasado a sed. Ahora el comando ‘n’ vuelve a ser ejecutado, luego ‘d’, ‘n’, y así sucesivamente.

Para hacerlo más corto: ‘n’ imprime la línea actual y ‘d’ vacía la línea, deshaciendo el doble espaciado.

5. Insertar una línea en blanco sobre cada línea que coincida con “regex”.

sed '/regex/{x;p;x;}'

En este caso utiliza la operación de restricción junto a dos nuevos comandos ‘x’ y ‘p’. El comando ‘x’ intercambia el hold buffer con el pattern space. El comando ‘p’ duplica la entrada, por lo que imprime el pattern space completo. Este one-liner funciona de la siguiente manera: una línea es leída en el pattern space, entonces el comando ‘x’ intercambia con el hold buffer que está vacío. A continuación el comando ‘p’ imprime ese vacío seguido de nueva línea, así que obtenemos una línea vacía impresa antes de la línea actual. . Entonces ‘x’ intercambia nuevamente el hold buffer (que ahora contiene la línea) con el pattern space. No hay más comandos así que sed imprime el pattern space. Obtenemos entonces una nueva línea seguida de la línea que coincidía con regex o en otras palabras, una línea en blanco sobre cada línea procesada.

También note los { … }. Esto es agrupamiento de comandos. Quiere decir: “ejecute todos los comandos en {} sobre la línea que coincida con regex.

6. Insertar una línea en blanco debajo de cada línea que coincida con “regex”.

sed '/regex/G'

Este one-liner combina el comando ‘G’ descripto en #1 con que la línea coincida con /regex/, sed agrega una nueva línea al pattern space. Las demás líneas que no coincidan con /regex/ simplemente son mostradas sin ninguna modificación.

7. Insertar una línea en blanco encima y debajo de cada línea que coincida con “regex”.

sed '/regex/{x;p;x;G;}'

En este caso se combinan los one-liners #5, #6 and #1. Las líneas que coincidan con /regex/ obtienen una nueva línea agregada antes y otra después.

Numeración.

8. Numerar cada linea de un archivo (filename). Alineación a la izquierda del número.

sed = filename | sed 'N;s/\n/\t/'

En este caso en realidad son dos one-liners separados. El primero usa un nuevo comando llamado ‘=’. Este comando opera directamente en el output stream e imprime el número de línea actual. No hay manera de capturar el número de línea actual en el pattern space. Por eso es que se llama al segundo one-liner. La salida del primero es redireccionada a la entrada del segundo. El segundo usa otro comando nuevo ‘N’. El comando ‘N’ agrega una nueva línea y la siguiente línea al pattern space. Entonces el famoso comando ‘s/\n/\t/’ es ejecutado el cual reemplaza el caracter recién agregado de nueva línea con un tabulador. Luego de estas operaciones, las líneas son impresas.

Para hacer más claro que hace ‘=’, veamos esto:

line one
line two
line three

Corriendo el primer one-liner ‘sed = filename’, produce la salida:

1
line one
2
line two
3
line three

Ahora el comando ‘N’ del segundo, junta estas líneas con un caracter de nueva línea:

1\nline one
2\nline two
3\nline three

Entonces ‘s/\n/\t/’ reemplaza cada nueva línea con un tabulador, así que obtenemos:

1     line one
2     line two
3     line three

Este ejemplo no es del todo exacto, ya que la unión de líneas con un caracter de nueva línea ocurre línea tras línea, no en todas las líneas de una vez.

9. Numerar cada línea de un archivo (filename). Alineación a la derecha.

sed = filename | sed 'N; s/^/     /; s/ *\(.\{6,\}\)\n/\1  /'

Este one-liner es también una combinación. El primero numera las líneas igual que #8. El segundo usa ‘N’ para unir la línea que contiene el número con la actual. Luego usa dos comandos substitutos para alinear a la derecha los números. Primero ‘s/^/ / agrega 5 espacios en blanco al inicio de la línea. Luego ‘s/ *\(.\{6,\}\)\n/\1 /’ captura al menos seis símbolos antes de llegar al caracter de nueva línea y reemplaza esa captura más el caracter de nueva línea con la referencia hacia atrás ‘/1’. Luego agrega dos espacios finales para separar el número del contenido de la línea.

Es más sencillo ver un ejemplo que leer la explicación. Para claridad, se reemplaza ‘\n’ por ‘@’ y los espacios por ‘-‘.

$ echo "-----12@contents" | sed 's/-*\(.\{6,\}\)@/\1--/'
----12--contents

La expresión regular ‘-*\(.\{6,\}\)@’ indica a sed que un espacio ‘-‘ seguido de al menos 6 caracteres seguido de una nueva línea ‘@’. Sed los captura y los recuerda en \1. En el ejemplo coinciden el primer espacio ‘-‘ (la parte ‘-*’), entonces los siguientes seis caracteres ‘—- 12’ y ‘@’. Ahora se reemplaza la parte coincidente de la cadena ‘—-12@’ con el contenido capturado que es ‘—-12’ más dos espacios extra. El resultado final es que ‘—-12@’ se reemplaza con ‘—-12–‘.

10. Numerar cada línea no vacía de un archivo (filename).

sed '/./=' filename | sed '/./N; s/\n/ /'

Nuevamente son dos one-liners. La salida del primero es enviada al segundo. El primero filtra todas las líneas que tengan al menos un caracter. Cuando una línea vacía (con solo el caracter de nueva línea) es enviada al pattern space, el caracter de nueva línea es eliminado. El segundo one-liner hace lo mismo que #8, excepto que solo las líneas numeradas son unidas e impresas.

11. Contar el número de líneas en un archivo (emula “wc -l”).

sed -n '$='

En este caso se usa el switch “-n” para modificar el comportamiento de sed. Este switch le indica a sed que no envíe la línea a la salida luego de que haya sido procesada en el pattern space. La única manera de hacer que sed muestre una salida cuando existe el switch “-n” es usar un comando que modifique el output stream directamente (‘=’, ‘a’, ‘c’, ‘i’, ‘I’, ‘p’, ‘P’, ‘r’ y ‘w’).En este one-liner el comando ‘$’ es en realidad una restricción al aparecer junto a ‘=’. El comando ‘=’ muestra el número de línea actual, pero al ser aplicado a ‘$’ que es la última línea, sólo se imprime el número de la última línea del archivo.

Conversión y Sustitución de Texto

12. Convertir caracteres de nueva línea de DOS/Windows (CRLF) a Unix (LF).

sed 's/.$//'

Este asume que todas las líneas terminan con CR+LF (carriage return + line feed o retorno de carro + nueva línea) y que estamos en un ambiente Unix. Una vez que la línea es ingresada al pattern space, la nueva línea es descartada, así que nos quedan líneas terminadas en CR. El comando ‘s/.$//’ borra el último caracter que coincida con el último caracter de la línea (regex ‘.$’) y lo substituye con nada. Ahora cuando el pattern space muestra su salida, es agregada la nueva línea y nos queda un caracter LF.

13. Otro modo de convertir DOS/Windows CRLF a Unix LF.

sed 's/^M$//'

Este one-liner nuevamente asume que estamos en un ambiente Unix. Elimina el caracter de control de retorno de carro ^M. Usualmente puedes ingresar un caracter de control ^M literalmente pulsando Ctrl-V y luego Ctrl-M.

14. Otra forma más de convertir DOS/Windows CRLF a Unix LF.

sed 's/\x0D$//'

Este one-liner asume que estamos en un ambiente Unix y además que usa una versión de sed que soporta códigos de escape hexadecimales, tales como GNU sed. El valor hexadecimal para CR es 0×0D (13 decimal). En este caso se elimina ese caracter.

15-17. Convertir Unix LF a DOS/Windows CRLF.

sed "s/$/`echo -e \\r`/"

Este one-liner también asume que estamos en un ambiente Unix. Utiliza la llamada de shell ‘echo -e \\r’ para insertar un retorno de carro en la expresión de sed. El comando “s/$/char/” agrega este caracter obtenido al final del pattern space.

18. Otra forma de convertir Unix LF a DOS/Windows CRLF.

sed 's/$/\r/'

Este one-liner asume que utilizamos GNU sed. Esta versión es más inteligente que otras versiones ya que puede utilizar códigos de escape en la parte de reemplazo.

19. Convertir Unix LF a DOS/Windows CRLF desde DOS/Windows.

sed "s/$//"

Este one-liner trabaja desde DOS/Windows. Reemplaza nada con nada y envía la línea al output stream donde se agrega el caracter CRLF.

20. Otra forma de convertir Unix LF a DOS/Windows CRLF desde DOS/Windows.

sed -n p

Este similar a #19. También la forma más corta de hacer lo mismo es:

sed ''

21. Convertir DOS/Windows LF a formato Unix CRLF desde DOS/Windows.

sed "s/\r//"

Eric dice que este one-liner trabaja solo con UnxUtils v4.0.7 o superior. En este caso el caracter de retorno de carro es quitado de las líneas. Luego, cuando son impresas el CRLF es agregado automáticamente.

Eric también menciona que la única manera de convertir LF a CRLF en DOS es usar tr:

tr -d \r <infile >outfile

22. Borrar espacios iniciales (tabs y espacios) de cada línea.

sed 's/^[ \t]*//'

Muy simple, busca al inicio de cada línea una coincidencia de cero o más espacios y tabuladores y los reemplaza con nada, los borra.

23. Borrar espacios finales (tabs y espacios) de cada línea.

sed 's/[ \t]*$//'

Este es muy similar a #22. Realiza la misma sustitución simplemente buscando cero o más espacios y tabuladores al final de cada línea y reemplazándolos con nada, borrándolos.

24. Borrar espacios iniciales y finales de cada línea.

sed 's/^[ \t]*//;s/[ \t]*$//'

En este caso combina #22 y #23. Primero elimina los espacios iniciales, luego elimina los finales.

25. Insertar cinco espacios al principio de cada línea.

sed 's/^/     /'

Busca el inicio de la línea (^) que es un caracter de null-string y lo reemplaza por cinco espacios.

26. Alinear a la derecha en un ancho de 79 columnas.

sed -e :a -e 's/^.\{1,78\}$/ &/;ta'

Este one-liner utiliza una nueva opción de línea de comando y dos nuevos comandos. La opción de línea de comando es ‘-e’, que permite escribir los comandos por separados. En lugar de utilizar ; se utiliza la opción -e para clarificar y hacerlo más legible. En este caso, el primer -e crea una etiqueta llamada “a” usando el comando “:”. El segundo “-e” utiliza un nuevo comando ‘t’. Este comando se dirige a una etiqueta si el último comando ha modificado el pattern space. Esta técnica de bifurcación puede ser usada para crear bucles dentro de sed. En este one-liner, el comando pasa la cadena y la alinea a la derecha hasta que el total de la cadena excede 78 caracteres. El símbolo ‘&’ en el comando de sustitución indica la cadena que ha coincidido.

Traducido a lenguaje moderno, se vería como esto:

while (str.length() <= 78) {
    str = " " + str
}

27. Centrar todo el texto en la mitad de 79 columnas.

sed  -e :a -e 's/^.\{1,77\}$/ & /;ta'

Este es muy similar al #26, sólo que en lugar de rellenar a la izquierda de la línea lo va realizando a ambos lados hasta que alcanza al menos 77 caracteres. Entonces otros dos espacios son agregados en la última iteración y crece hasta 79 caracteres.

Otro modo de hacer lo mismo sería:

sed  -e :a -e 's/^.\{1,77\}$/ &/;ta' -e 's/\( *\)\1/\1/'

Este ejemplo va añadiendo espacios al comienzo de la cadena hasta que ésta llega a 78 caracteres. Entonces el comando adicional ‘s/\( *\)\1/\1/’ divide los espacios en blanco inciales a la mitad.

28. Sustituir (buscar y reemplazar) la primera ocurrencia de “foo” con “bar” en cada línea.

sed 's/foo/bar/'

Este la manera más simple posible. Utiliza el comando sustituir y lo aplica en cada línea, así se reemplaza “foo” con “bar”.

29. Sustituir (buscar y reemplazar) la cuarta ocurrencia de “foo” con “bar” en cada línea.

sed 's/foo/bar/4'

Este one-liner utiliza una bandera para el comando de sustitución. Sin esta bandera la primera ocurrencia sería cambiada. Con una bandera numérica como “/1”, “/2”, etc. y sólo esa ocurrencia será cambiada. En este caso hay un “/4” con lo cual la cuarta aparición será reemplazada.

30. Sustituir (buscar y reemplazar) todas las ocurrencias de “foo” con “bar” en cada línea.

sed 's/foo/bar/g'

Este one-liner utiliza otra bandera, en este caso la “/g” que indica global. Con una bandera global las sustituciones son para todas las ocurrencias.

31. Sustituir (buscar y reemplazar) la primera ocurrencia de una ocurrencia repetida de “foo” con “bar” en cada línea.

sed 's/\(.*\)foo\(.*foo\)/\1bar\2/'

Intentemos entender con este ejemplo

$ echo “this is foo and another foo quux” | sed ‘s/\(.*\)foo\(.*foo\)/\1bar\2/’

this is bar and another foo quux

Como puedes ver, en la línea hay dos apariciones de foo, pero solo la primera es reemplazada.

32. Sustituir (buscar y reemplazar) la última ocurrencia de “foo” con “bar” en cada línea.

sed 's/\(.*\)foo/\1bar/'

En este caso se utiliza un grupo de captura el cual guarda todo hasta “foo”. Reemplaza la línea con lo capturado y agrega “bar”.

33. Sustituir (buscar y reemplazar) todas las ocurrencias de “foo” con “bar” en todas las líneas que contengan “baz”.

sed '/baz/s/foo/bar/g'

En este one-liner se usa una expresión regular para restringir la sustitución a las líneas que contengan “baz”. El resto de las líneas (donde no coincida) simplemente serán impresas.

34. Sustituir todas las ocurrencias de “foo” con “bar” en todas las líneas que NO contengan “baz”

sed '/baz/!s/foo/bar/g'

Los comandos de sed pueden ser negados utilizando “!”.

35. Cambiar los textos “scarlet”, “ruby” o “puce” a “red”.

sed 's/scarlet/red/g;s/ruby/red/g;s/puce/red/g'

En este caso se usan tres sustituciones consecutivas. La primera reemplaza “scarlet” con “red”, la segunda reemplaza “ruby” con “red” y la última reemplaza “puce” con “red”.

Si estás usando GNU sed, se puede realizar más sencillamente:

gsed 's/scarlet\|ruby\|puce/red/g'

GNU sed provee expresiones regulares más avanzadas. Note que utiliza “\|” como un o (or) lógico.

36. Invertir el orden de las líneas (emular el comando tac).

sed '1!G;h;$!d'

Este one-liner actúa como la utilidad tac. Es más sencillo explicarlo mediante un ejemplo:

Supongamos que tenemos un archivo con 3 líneas:

$ cat file
foo
bar
baz

Ejecutando sed, se invierte el orden de las líneas:

$ sed '1!G;h;$!d' file
baz
bar
foo

La primera parte “1!G” es aplicada a todas las líneas excepto la primera. El segundo comando “h” se aplica a todas las líneas y el tercer comando “$!d” se aplica a todas las líneas excepto la última.

Veamos la ejecución:

Línea 1: Sólo “h” se aplica a la primera línea. Ésta se copia al hold buffer. El hold buffer ahora contiene “foo”. Al aplicarse el comando “d” la salida es vacía.

Línea 2: El comando “G” es aplicado. Agrega el contenido del hold buffer al pattern space. El pattern space contiene ahora “bar\nfoo”. El comando “h” copia entonces “bar\nfoo” al hold buffer, finalmente no hay salida.

Línea 3: El comando “G” es aplicado y agrega el contenido del hold buffer a la tercera y última línea. El pattern space contiene “baz\nbar\nfoo”. Como es la última línea, “$!d” no se aplica y el pattern space es impreso. Se imprimen las líneas del archivo en orden inverso.

Aquí hay otra forma de realizar lo mismo:

sed -n '1!G;h;$p'

Se silencia la salida con el switch “-n” y se fuerza a escribir la salida con el comando “p” en la última línea.

Estos dos one-liners utilizan mucha memoria dado que mantienen el archivo completo en el hold buffer en orden inverso hasta el momento de su impresión. Como recomendación, trate de no utilizar estos one-liners cuando tenga que procesar archivos grandes.

37. Invertir una línea (emular el comando “rev”).

sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'

Este es bastante complicado. Vamos a re-formatearlo para ver mejor:

sed '
/\n/ !G
s/\(.\)\(.*\n\)/&\2\1/
//D
s/.//
'

La primer línea “/\n/ !G” agrega una nueva línea al final del pattern space si no hubiera ninguno.

La segunda línea “s/\(.\)\(.*\n\)/&\2\1/” es un simple s/// que agrupa el primer caracter como \1 y el resto como \2. Entonces se reemplaza toda la cadena con “&\2\1”, donde “&” es todo el texto (“\1\2”). Por ejemplo, si la cadena de entrada es “1234” luego de aplicar la expresión s///, se convertiría en”1234\n234\n1″.

La tercera línea es “//D”. Este es clave en este one-liner. Un patrón vacío // coincide con la última regex, sería lo mismo que: /\(.\)\(.*\n\)/D. El comando “D” elimina desde el comienzo hasta el caracter de nueva línea, entonces continúa la edición con el primer comando en el script. Crea un bucle. Mientras que /\(.\)\(.*\n\)/ sea cumplido, sed retomará todas las operaciones previas. Luego de varios ciclos, el texto en el pattern space se convierte en “\n43212”. Entonces /\(.\)\(.*\n\)/ falla y sed continúa con el siguiente comando.

La cuarta linea “s/.//” elimina el primer caracter en el pattern space que es un caracter de nueva línea (\n). El contenido en el pattern space se convierte en “4321″ el inverso de “1234”.

Ahí lo tienes, la línea ha sido invertida.

38. Unir un par de líneas (emular el comando “paste”).

sed '$!N;s/\n/ /'

En este caso se unirán dos líneas consecutivas con el comando “N”. Quedan unidas con un “\n” entre ellas. El comando sustituye este caracter con un espacio uniendo ambas líneas en una sola.

39. Agregar una línea a la próxima si ésta termina en backslash “\”.

sed -e :a -e '/\$/N; s/\\n//; ta'

La primera expresión crea una etiqueta ‘:a’. La segunda expresión verifica que la línea actual termine en backslash “\”. Si se cumple, une la línea con la siguiente utilizando el comando “N”, con lo cual los caracteres \ y \n son eliminados por “s/\\n//”. Con “t” se vuelve a iniciar el ciclo buscando otra línea que termine en \.

Aquí hay un ejemplo:

$ cat filename
line one \
line two
line three
$ sed -e :a -e '/\$/N; s/\\n//; ta' filename
line one line two
line three

Las líneas uno y dos son unidas ya que la primera termina en backslash.

40. Agregar una línea a la anterior si ésta comienza con un signo “=”.

sed -e :a -e '$!N;s/\n=/ /;ta' -e 'P;D'

Este one-liner también comienza creando una etiqueta. Entonces verifica que no sea la última línea y agrega la siguiente línea a la actual con el comando “N”. Si la línea comenzara con “=”, sed abre otros procesos para ver que haya más líneas que comiencen con “=”. Durante este proceso, una sustitución se ejecuta eliminado la nueva línea y el =. Si la sustitución falla, se imprime el pattern space, se vacía y se repite el proceso

Un ejemplo:

$ cat filename
line one
=line two
=line three
line four
$ sed -e :a -e '$!N;s/\n=/ /;ta' -e 'P;D' filename
line one line two line three
line four

41. Grupo de dígitos en una cadena numérica (poner comas de miles)

sed -e :a -e 's/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/;ta'

Este one-liner convierte una cadena numérica como “1234567″ a “1,234,567″.

Primero se crea una etiqueta. Luego captura dos grupos de dígitos. El primer grupo son todos los dígitos hasta los últimos tres. Los últimos tres dígitos son capturados en el segundo grupo. Entonces los dos grupos son separados por una coma. Luego las mismas reglas son aplicadas una y otra vez a la línea hasta que todos los números hayan sido agrupados de a tres.

El comando de sustitución “\1,\2” separa los grupos con una coma.

Un ejemplo rápido sería: una cadena como 12345678 se separaría en 12345,678. En la segunda aplicación de las reglas quedaría 12,345,678. Si se intenta aplicar las reglas nuevamente, dará error con lo cual se imprime y sed comienza a trabajar sobre la línea siguiente.

Si se utiliza GNU sed es más sencillo:

gsed ':a;s/\B[0-9]\{3\}\>/,&/;ta'

42. Agregar comas a número con punto decimal y signos +/-.

gsed -r ':a;s/(^|[^0-9.])([0-9]+)([0-9]{3})/\1\2,\3/g;ta'

Este trabaja únicamente en GNU sed. Trabaja sobre expresiones regulares extendidas usando el switch ‘-r’. Entonces hace un bucle sobre las líneas con tres grupos y separa los dos primeros del tercero con una coma

El primer grupo se asegura que ignoramos los caracteres no numéricos + o -. Si no hay caracteres iniciales, entonces comineza normalmente.

Una vez que los grupos han sido capturados como “\1\2,\3” la sustitución se realiza y se vuelve a comenzar hasta que toda la cadena haya sido procesada.

43. Agregar una línea en blanco luego de cada cinco líneas

sed 'n;n;n;n;G;'

El comando “n” es llamado cuatro veces. Cada vez que es llamado imprime el pattern space actual, lo vacía y lee la siguiente línea. Luego de ejecutarse cuatro veces y la quinta línea está dentro del pattern space, el comando “G” es llamado agregando una nueva línea a esta última. Entonces la siguiente ronda de “n” es procesada, luego “G” y así sucesivamente.

En GNU sed se puede realizar así:

gsed '0~5G'

Nota del Traductor: Esta ha sido la parte I de la traducción.

13 comentarios (+¿añadir los tuyos?)

  1. Trackback: Sed en una-línea (sed one-liners) Parte II « Jinete del Dragon
  2. Trackback: Famous Sed One-Liners Explained, Part I - good coders code, great reuse
  3. Trackback: Sed en una-línea (sed one-liners) Parte III « Jinete del Dragon
  4. ivan
    May 28, 2012 @ 14:08:47

    hola gracias por las instrucciones
    como colocar un numero de lineas en blanco entre lineas de texto? es decir, separar las lineas texto entre sí dejando N lineas en blanco?

    Responder

    • jinetedeldragon
      May 29, 2012 @ 22:40:10

      Hola, lo mejor es “probar”.
      Si el caracter “$” representa el fin de línea y “\n” es el caracter de nueva línea, entonces puedes usar la búsqueda y reemplazo básico:
      sed ‘s/$/\n/g’ nombre-de-archivo

      Hago desglose para que se entienda:
      (s/) busca el final de línea ($/) y lo reemplaza por un retorno de carro y nueva línea (\n/) para todas las líneas del archivo (g)

      Si quisieras 5 líneas, sólo debes colocar 5 \n, así:
      sed ‘s/$/\n\n\n\n\n/g’ nombre-de-archivo

      Lo bueno de sed es que puedes probar hasta ver la información por pantalla como quieras y luego si redireccionarla a un archivo
      sed ‘s/$/\n\n\n\n\n/g’ nombre-de-archivo >> nuevo-archivo

      Saludos

      Responder

  5. jose vila
    Ene 26, 2014 @ 08:49:06

    ¿Como podria colocar una linea en blanco despues de la primera linea de un texto?
    Por ejemplo pasar de:

    juan
    Perez Galdos, 27
    Sevilla

    A:

    Juan

    Perez Galdos,27
    Sevilla

    Muchisimas gracias.

    Responder

  6. jose vila
    Ene 26, 2014 @ 11:06:07

    Por fin lo he encontrado… y me contesto yo:

    sed ‘2i\ \’ archivo

    Responder

  7. GIL
    Oct 09, 2014 @ 19:52:09

    hola que tal, mi duda es la siguiente;
    ¿Como puedo agregar por decir algo 5 lineas antes de una ocurrencia o una linea y dentro de esas 5 o n lineas nuevas agregar una secuencia de números?

    por ejemplo; el archivo tiene el siguiente formato…

    HEADER1, HEADER2, HEADER3
    5, NULL, NULL
    6, NULL, 52
    7,20,NULL
    ….

    y yo quiero por ejemplo insertar de la linea 0 a la linea 4, y entonces debiera quedar así;

    HEADER1, HEADER2, HEADER3
    0, NULL, NULL
    1, NULL, NULL
    2, NULL, NULL
    3, NULL, NULL
    4, NULL, NULL
    5, NULL, NULL
    6, NULL, 52
    7,20,NULL
    ….

    Responder

    • jinetedeldragon
      Oct 10, 2014 @ 16:04:53

      Creo que lo que buscas es más elaborado como para utilizar un one-liner.
      Deberías probar con un script que analice línea por línea y vaya comparando con un contador. Si falta, que agregue los datos faltantes.

      Responder

  8. Pablo
    Feb 06, 2015 @ 11:01:20

    Como puedo reemplazar con sed la siguiente cadena: “$ 1.700,50” por “£ 1.700,50” ? gracias!

    Responder

    • jinetedeldragon
      Mar 17, 2015 @ 13:29:51

      Para reemplazar caracteres especiales como $, debe “escaparse” con una \
      No se como reproducir el caracter £ dado que no lo tengo en mi teclado.
      Puedes intentar
      echo “$ 1.700,50” | sed ‘s/\$/£/g’
      o
      echo “$ 1.700,50” | sed ‘s/\$/\£/g’

      Responder

  9. Joaquín Ataz López
    Abr 03, 2015 @ 04:23:59

    Hola. Muy buen análisis. Afirmas que apenas hay documentación sobre sed en castellano, y como no hay en tu blog ningún correo electrónico al que me pueda dirigir (o yo no lo he visto), aprovecho ahora para comentarte que, hace unos años, yo escribí un texto de introducción a sed en castellano que puedes encontrar en http://webs.um.es/jal/docs/guia-sed.pdf.

    No es gran cosa y, obviamente, tu nivel está bastante por encima de esa guía, pero es posible que a algunos de los visitantes de esta página les sea útil

    Responder

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

Archivos

junio 2009
D L M X J V S
« May   Jul »
 123456
78910111213
14151617181920
21222324252627
282930  
A %d blogueros les gusta esto: