text-processing – Sed: reemplaza las primeras k instancias de una palabra en el archivo

Pregunta:

Quiero reemplazar solo las primeras k instancias de una palabra.

¿Cómo puedo hacer esto?

P.ej. Digamos que el archivo foo.txt contiene 100 instancias de apariciones de la palabra 'linux'.

Necesito reemplazar solo las primeras 50 ocurrencias.

Respuesta:

La primera sección a continuación describe el uso de sed para cambiar las primeras k ocurrencias en una línea. La segunda sección amplía este enfoque para cambiar solo las primeras k ocurrencias en un archivo, independientemente de la línea en la que aparezcan.

Solución orientada a líneas

Con sed estándar, hay un comando para reemplazar la k-ésima aparición de una palabra en una línea. Si k es 3, por ejemplo:

sed 's/old/new/3'

O bien, se pueden reemplazar todas las apariciones con:

sed 's/old/new/g'

Ninguno de estos es lo que quieres.

GNU sed ofrece una extensión que cambiará la k-ésima aparición y todo lo que sigue. Si k es 3, por ejemplo:

sed 's/old/new/g3'

Estos se pueden combinar para hacer lo que desee. Para cambiar las 3 primeras apariciones:

$ echo old old old old old | sed -E 's/\<old\>/\n/g4; s/\<old\>/new/g; s/\n/old/g'
new new new old old

donde \n es útil aquí porque podemos estar seguros de que nunca ocurre en una línea.

Explicación:

Usamos tres comandos de sustitución sed :

  • s/\<old\>/\n/g4

    Esta es la extensión GNU para reemplazar la cuarta y todas las apariciones posteriores de la old con \n .

    La función de expresión regular extendida \< se utiliza para coincidir con el comienzo de una palabra y \> para coincidir con el final de una palabra. Esto asegura que solo coincidan las palabras completas. La expresión regular extendida requiere la opción -E para sed .

  • s/\<old\>/new/g

    Solo quedan las tres primeras apariciones de lo old y esto las reemplaza todas por new .

  • s/\n/old/g

    La cuarta y todas las apariciones restantes de la old se reemplazaron con \n en el primer paso. Esto los devuelve a su estado original.

Solución que no es GNU

Si GNU sed no está disponible y desea cambiar las primeras 3 apariciones de old a new , utilice tres comandos s :

$ echo old old old old old | sed -E -e 's/\<old\>/new/' -e 's/\<old\>/new/' -e 's/\<old\>/new/'
new new new old old

Esto funciona bien cuando k es un número pequeño pero escala deficientemente a k grande.

Dado que algunos seds que no son de GNU no admiten la combinación de comandos con punto y coma, cada comando aquí se presenta con su propia opción -e . También puede ser necesario verificar que su sed admita los símbolos de límites de palabras, \< y \> .

Solución orientada a archivos

Podemos decirle a sed que lea todo el archivo y luego realice las sustituciones. Por ejemplo, para reemplazar las tres primeras apariciones de old usando un sed estilo BSD:

sed -E -e 'H;1h;$!d;x' -e 's/\<old\>/new/' -e 's/\<old\>/new/' -e 's/\<old\>/new/'

Los comandos sed H;1h;$!d;x leen todo el archivo en formato.

Debido a que lo anterior no usa ninguna extensión GNU, debería funcionar en BSD (OSX) sed. Tenga en cuenta, pensó, que este enfoque requiere un sed que pueda manejar largas filas. GNU sed debería estar bien. Aquellos que usan una versión de sed que no sea GNU deben probar su capacidad para manejar largas filas.

Con un sed de GNU, podemos seguir usando el truco g descrito anteriormente, pero con \n reemplazado por \x00 , para reemplazar las tres primeras apariciones:

sed -E -e 'H;1h;$!d;x; s/\<old\>/\x00/g4; s/\<old\>/new/g; s/\x00/old/g'

Este enfoque escala bien a medida que k aumenta. Sin embargo, esto supone que \x00 no está en su cadena original. Dado que es imposible poner el carácter \x00 en una cadena bash, esto suele ser una suposición segura.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top

web tasarım