Invertir un tiempo en aprender unas cuantas expresiones regulares y el uso de sed merece la pena. En el futuro nos va ahorrar con creces mucho más tiempo del invertido. Para ver el potencial de sed a la hora de modificar el contenido de ficheros, vamos a utilizar como ejemplo unos fragmentos del texto «The Zen of Python» que he modificado para los ejemplos y que pondré en el fichero sed-zen.txt:
Complex is better than simple. Flat is better than nested. Sparse is better than dense. Readability doesn’t count. Yeah Yeah Yeah Although practicality beats Errors should never pass silently noes. I don’t know what I am doing.
Evidentemente ese texto está mal. El original sería:
Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced.
Basándonos en el texto correcto original, los fallos del inicial serían:
(Falta línea) (Falta línea) Complex is better than simple. (Modificado) Flat is better than nested. Sparse is better than dense. Readability doesn’t count. (Modificado) (Falta línea) Yeah Yeah Yeah (Sobra línea) Although practicality beats (Falta palabra final) Errors should never pass silently noes. (Sobra la última palabra) I don’t know what I am doing. (Sobra línea) (Falta línea)
Para dejarlo igual que el texto original, utilizaremos expresiones regulares y sed. Por supuesto además de los ejemplos puestos en este artículo habrá más maneras distintas de utilizar sed y las expresiones regulares para lograr el objetivo.
Antes de empezar, 2 opciones básicas de sed a tener en cuenta:
- -i para modificar el contenido del fichero del que editamos el flujo de datos. Si no incluímos esta opción sed modificará el flujo en la salida estándar (stdout, por defecto nuestra pantalla) pero no lo hará en el fichero. Por tanto, sólo incluir la opción -i cuando estemos seguros de que queremos modificar el fichero con el que estamos trabajando.
No obstante, al modificar el contenido de un fichero con -i podemos hacer una copia de respaldo del fichero original añadiendo simplemente un sufijo a la opción de la siguiente manera:
sed -i.backup -e '1,5d' sed-zen.txt
Esto habrá creado el fichero sed_sed-zen.txt.backup con el contenido previo a la modificación realizada con sed.
- -e Procede la expresión regular (o expresiones) que van a modificar el flujo.
Añadir contenido
Como hemos visto en el texto faltan dos líneas al principio, añadimos la primera de la siguiente manera:
sed -i -e '1i Beautiful is better than ugly.\' sed-zen.txt
Añadimos la segunda:
sed -i -e '2i Explicit is better than implicit.\' sed-zen.txt
¿Qué hay de la línea del final? Podemos hacer uso del comodín $ para indicar el final del fichero:
sed -i -e '$ a\Unless explicitly silenced.' sed-zen.txt
También hemos visto que faltaba una línea más o menos a mitad del texto. Podríamos proceder de dos maneras: por la cuenta de la vieja, para ver en qué línea tendríamos que añadir el texto correspondiente; o bien especificando a sed que después de un determinado patrón añada la línea de texto que falta. En este caso la línea que falta va después de «Readability doesn’t count»
sed -i -e "/Readability doesn't count./a Special cases aren't special enough to break the rules." sed-zen.txt
Como en el texto había apóstrofes, nota cómo he utilizado la doble comilla en este caso después de la opción -e para indicar las expresiones a evaluar.
Finalmente, tenemos el caso de «Although practicality beats». En esa línea falta la palabra purity. La añadimos de la siguiente manera:
sed -i -e 's/beats/beats purity/' sed-zen.txt
Modificar contenido
Ahora vamos a poner en orden todos los elementos que aparecen modificados. Por ejemplo tenemos el caso de «Complex is better than simple» que debería ser «Simple is better than complex». Podemos modificarlo de la siguiente manera:
sed -i -e '0,/Complex/ s/Complex/Simple/' sed-zen.txt
La primera expresión 0,/Complex/ nos indica que es la primera ocurrencia (0) Complex. Ahora bien, nos queda «Simple is better than simple», lo que tenemos que hacer ahora es sustituir el simple final con complex:
sed -i -e 's/simple/complex/' sed-zen.txt
Por otro lado «Readability doesn’t count.» debería ser «Readability counts.», así que para modificarlo haremos lo siguiente:
sed -i -e 's/Readability.*/Readability counts/g' sed-zen.txt
Básicamente lo que estamos haciendo es buscar el patrón «Readability» seguido de «lo que sea» representado por .* y sobreescribir la línea con el texto deseado. Muy parecido a lo que hicimos con la línea «Although practicality beats» como podrás recordar.
Eliminar contenido
También tenemos cierto contenido que debemos eliminar. Las dos líneas que sobran son «I don’t know what I am doing.» y «Yeah Yeah Yeah». Podemos eliminarlas buscando el patrón correspondiente:
sed -i -e '/Yeah Yeah Yeah/d' sed-zen.txt sed -i -e "/I don't know what I am doing/d" sed-zen.txt
También podríamos hacerlo acudiendo al número de línea, por ejemplo:
sed -i -e '9d' sed-zen.txt
Por último sobra la palabra «noes» en la línea «Errors should never pass silently noes.» La podemos eliminar así:
sed -i -e 's/noes//g' sed-zen.txt
Otros tips útiles
Además de las posibilidades de sed mencionadas anteriormente hay muchas otras. Aquí algunos ejemplos que pueden resultar útiles según en algún momento:
Para convertir el texto en minúsculas a mayúsculas:
sed -i -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' sed-zen.txt
Al revés, de mayúsculas a minúsculas:
sed -i -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' sed-zen.txt
Existen formas más abreviadas de hacerlo:
# De minus a mayus sed -i -e 's/\(.*\)/\U\1/' sed-zen.txt # De mayus a minus sed -i -e 's/\(.*\)/\L\1/' sed-zen.txt
Para añadir comentario (#) al inicio de todas las líneas:
sed -i -e 's/^/#/' sed-zen.txt
Añadir comentario al inicio de la segunda línea:
sed -i -e '2 s/^/#/' sed-zen.txt
Para eliminar un rango de líneas, por ejemplo de la primera a la quinta (incluídas):
sed -i -e '1,5d' sed-zen.txt
Eliminar los comentarios de un fichero:
sed -i -e '/^#/d' sed-zen.txt
Además de todos estos, hay muchos más que podrás sacar tú mismo combinando distintas formas y expresiones.