Suele ser habitual encontrar en las explicaciones de Internet la necesidad de sustituir algún dato en un fichero de texto obligando para ello al usuario a localizar el archivo, hacer una búsqueda en su contenido y hacer el cambio pedido sin equivocarse en ninguno de los pasos.
No es una tarea excesivamente complicada pero si que puede resultar aburrida, innecesaria y propensa a errores.
Para uno de los artículos que voy a publicar próximamente se requiere hacer una operación de este tipo y, como imagino que no será la última vez que tengamos que hacer algo así he optado por publicar este artículo en el que explico cómo realizar, con una sola instrucción, algunas operaciones básicas sobre el contenido de un fichero de texto desde la línea de comandos.
Texto de ejemplo
Sea el contenido del fichero /tmp/frases.txt, que usaremos en nuestros ejemplos, el siguiente
Francisco compra el Pan Odio que me despierte el panadero Compra pan cuando estés acampando Tengo congelado algo de pan de la semana pasada
Veamos qué podemos hacer con él
Buscar y reemplazar un texto
Sustituir texto
Si lanzamos desde la terminal un
sed 's/pan/XXXX/g' /tmp/frases.txt
obtendremos como resultado
Francisco compra el Pan Odio que me despierte el XXXXadero Compra XXXX cuando estés acamXXXXdo Tengo congelado algo de XXXX de la semana pasada
Ignorar mayúsculas y minúsculas
En la primera frase se nos ha escapado Pan para evitarlo debemos lanzar el comando sed del siguiente modo
sed 's/pan/XXXX/gi' /tmp/frases.txt
NOTA: Observa el /gi al final del patrón
obtendremos como resultado
Francisco compra el XXXX Odio que me despierte el XXXXadero Compra XXXX cuando estés acamXXXXando Tengo congelado algo de XXXX de la semana pasada
Sustituir palabras completas
En los ejemplos anteriores encontramos que se han producido sustituciones de texto en palabras como panadero y acampando. Para evitarlo utilizaremos /b del siguiente modo
sed 's/pan\b/XXXX/gi' /tmp/frases.txt
obteniendo como resultado
Francisco compra el XXXX Odio que me despierte el panadero Compra XXXX cuando estés acampando Tengo congelado algo de XXXX de la semana pasada
Líneas de inicio y fin
Si queremos que sólo se cambie el texto comprendido entre dos líneas del fichero (ambas incluidas) deberemos recurrir al siguiente comando
sed '2,3s/pan/XXXX/gi' /tmp/frases.txt
NOTA: observa el 2,3 que indica que los cambios deben realizarse en las líneas 2 y 3 dejando inalteradas el resto.
NOTA: observa igualmente que he quitado el /b para que sustituya cualquier ocurrencia de pan sin tener en cuenta si es, o no, una palabra completa o está dentro de otra; de este modo conseguimos que se vean cambios en ambas líneas.
El resultado del comando anterior sería
Francisco compra el Pan Odio que me despierte el XXXXadero Compra XXXX cuando estés acamXXXXdo Tengo congelado algo de pan de la semana pasada
De una línea hasta el final
Si queremos cambiar todas las ocurrencias desde una línea concreta hasta el final, lanzaremos el comando del siguiente modo
sed '2,$ s/pan/XXXX/gi' /tmp/frases.txt
observando que se ha utilizado $ en lugar del número de línea final para indicar que debe llegar hasta el final del fichero.
El resultado sería
Francisco compra el Pan Odio que me despierte el XXXXadero Compra XXXX cuando estés acamXXXXdo Tengo congelado algo de XXXX de la semana pasada
Conclusión
Espero que el «tochaco» de comandos y ejemplos os sirva de referencia y os ayude a comprender cómo realizar sustituciones en el contenido de un fichero de texto plano utilizando la línea de comandos.
Como indico mi objetivos es poder utilizarlo como referencia en otros artículos (evitando de este modo a los lectores tener que realizar tareas propensas a error) pero nadie evita que este conocimiento pueda ser aplicado igualmente a scripts en bash que simplifiquen dichos procesos.
Excelente!!! La verdad es que en este blog siempre encuentro tips muy utiles y detallados que ayudan mucho a comprender que estamos haciendo.
Gracias
Me gustaMe gusta
Me alegra que te guste el contenido @LifyDoubleasPain
Un saludo y bienvenido a este rincón de la web
Me gustaMe gusta
Perdone mi indiscrección, pero llevo rato buscando por todo google una forma de usar sed que haga… por ejemplo en su frase de ejemplo , borrar todo lo que haya entre la palabra ‘que’ y ‘algo’. Primero borrando ambas incluidas, y segundo sin borrarlas.
¿Esos dos ejemplos, como se hacen? Espero pueda ayudarme,Gracias.
Me gustaMe gusta
La verdad es que resulta interesante la pregunta que planteas; tendría que jugar un rato con expresiones regulares por lo que no voy a poder darte una solución inmediata.
Me anoto echarle un vistazo y te cuento si encuentro algo.
Un saludo @Markus
Me gustaMe gusta
Gracias por contextarme.
La verdad que jugando jugando he llegado a una solución, pero tiene un pequeño fallo, le mostrare con un ejemplo:
La mariposa era bonita, con un ala rosa y un ala azul.
Si por ejemplo yo quisiera borrar(o sustituir) todo lo que hay entre ‘era’ y ‘ala’… tendría problemas con el segundo ‘ala’ si escribo:
sed ‘s/era.*ala//g’
por que efectivamente me borra todo desde ‘era’ hasta ‘ala’ pero no el primero, si no el segundo ‘ala’, por lo que pienso que debo expecificar que quiero que sea siempre hasta el ‘primer ala’ que encuentre.
Si se pregunta ¿para que demonios necesito hacer esto? ¿Para que me voy a comer la cabeza por algo así?
Aquí le explico mi meta:
Muchas veces usando Kompiz para crear webs de manera sencilla observo que en el modo wysiwyg va dotando a todas las etiquetas html de estilos css…. de manera style=»lo que sea chim pum; lo que sea mas; etc…;» cosa que no me gusta por que yo prefiero usar una hoja css a mi manera, yo quería hacer un script en bash que cogiera el archivo html que acabo de crear, y le borre toooooooodas las sentencias de estilos, y con esta sentencia sed:
sed ‘s/style\=\».*\;\»//g’
efectivamente encuentra muchísimos ;» finales y me borra casi todo lo que encuentra en cada linea… al igual que pasa con el problema de ‘ala’ de arriba, es muy fustrante, llevo tres días con esto… y son tantas html que quiero editar… que mejor hubiese empezado hace tres días a borrarlas una a una…
Bueno, espero que le interese lo demasiado el asunto, como para que le pueda dedicar algún minutejo más próximamente.
Gracias por todo.
Markus
Por cierto, le felicito por el blog. Me ha gustado mucho. Saludos
Me gustaMe gusta
Bueno, sólo comentarle que ya lo he solucionado
Frase:
La mariposa era bonita, con un ala rosa y un ala azul.
Para borrar o sustituir lo que hay entre «era» y el primer «ala» sin borrar ambas palabras:
s/(?<=str1)(?:[^])*?(?=str2)//g
Y para borrar o sustituir lo que hay entre "era" y el primer "ala" borrando ambas palabras inclusive:
s/ era="[^"]*ala//g
Por lo tanto para borrar las lineas de estilo en las tags html sería
s/( cellspacing| bordercolor| border| style)="[^"]*"//g
Un saludo, y gracias por todo.
Hasta pronto.
Me gustaMe gusta
Gracias a ti @Markus por tomarte la molestia de comentar la solución (tengo que probarla en cuanto encuentre un hueco).
Estuve mirando varias soluciones pero el que sed sea «greedy» me estaba fastidiando el resultado 😦
Enhorabuena y perdona que no haya podido dedicarle tanto tiempo como me hubiese gustado
Me gustaMe gusta
Eres todo un gurú @Markus, estuvo dos días buscando por algo así hasta que encontré tu blog, no hay con que pagarte. . .
Me gustaMe gusta
Hola,
Alguno sabe si se le puede especificar al sed que realize el cambio solo la primera o la quinta vez que lo encuentra?
Me imagino que indicandole la linea podría funcionar, pero que pasaría si no sabes en que linea esta?
Gracias.
Me gustaMe gusta
Hola estimado, como haría para sustituir un texto especifico con espacios, puntos, igual y otros por ejemplo:
hola.1.adios=despedida
por el siguiente
hola.1.adios=saludo
El texto no siempre esta en la misma linea y es en diferentes equipos por eso no puedo hacerlo por linea el reemplazo.
Saludos,
Me gustaMe gusta
Yo optaría por utilizar expresiones regulares con la técnica descrita en el artículo.
Para tu problema en concreto necesitaría tener más detalles:
Interesante propuesta Jorge, igual tengo que dedicarte un nuevo artículo ¿Qué os parece? 😉
Me gustaMe gusta