Quiero reemplazar solo las primeras k
instancias de una palabra.
¿Cómo puedo hacer esto?
P.ej. Dicho archivo foo.txt
contiene 100 instancias de la palabra 'linux'.
Necesito reemplazar las primeras 50 ocurrencias solamente.
text-processing
sed
awk
narendra-choudhary
fuente
fuente
Respuestas:
La primera sección a continuación describe el uso
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 en qué línea 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:O bien, uno puede reemplazar todas las ocurrencias con:
Ninguno de estos es lo que quieres.
GNU
sed
ofrece una extensión que cambiará la k-ésima ocurrencia y todo después de eso. Si k es 3, por ejemplo:Estos se pueden combinar para hacer lo que quieras. Para cambiar las 3 primeras ocurrencias:
donde
\n
es útil aquí porque podemos estar seguros de que nunca ocurre en una línea.Explicación:
Utilizamos tres
sed
comandos de sustitución:s/\<old\>/\n/g4
Esta es la extensión GNU para reemplazar el cuarto y todos los sucesos posteriores de
old
con\n
.La función de expresión regular extendida
\<
se usa para hacer coincidir el comienzo de una palabra y\>
para hacer coincidir el final de una palabra. Esto asegura que solo las palabras completas coincidan. La expresión regular extendida requiere la-E
opciónsed
.s/\<old\>/new/g
Solo quedan las tres primeras ocurrencias
old
y esto las reemplaza a todasnew
.s/\n/old/g
El cuarto y todos los sucesos restantes de
old
fueron reemplazados por\n
en el primer paso. Esto los devuelve a su estado original.Solución no GNU
Si GNU sed no está disponible y desea cambiar las primeras 3 apariciones de
old
anew
, utilice tress
comandos:Esto funciona bien cuando
k
es un número pequeño pero se escala deficiente a grandek
.Dado que algunos seds que no son GNU no admiten la combinación de comandos con punto y coma, cada comando aquí se presenta con su propia
-e
opción. También puede ser necesario verificar quesed
admite los símbolos de límite 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 ocurrencias del
old
uso de un sed de estilo BSD:Los comandos sed
H;1h;$!d;x
leen todo el archivo.Como lo anterior no utiliza ninguna extensión GNU, debería funcionar en sed BSD (OSX). Tenga en cuenta, pensó, que este enfoque requiere un
sed
que puede manejar largas colas. GNUsed
debería estar bien. Aquellos que usan una versión de GNU nosed
deben probar su capacidad para manejar largas colas.Con un GNU sed, podemos usar el
g
truco descrito anteriormente, pero con\n
reemplazado por\x00
, para reemplazar los primeros tres casos:Este enfoque se escala bien y se
k
hace grande. Sin embargo, esto\x00
supone que no está en su cadena original. Dado que es imposible poner el carácter\x00
en una cadena bash, esto generalmente es una suposición segura.fuente
tr '\n' '|' < input_file | sed …
. Pero, por supuesto, eso convierte toda la entrada en una línea, y algunos seds que no son GNU no pueden manejar líneas arbitrariamente largas. (2) Usted dice: "... arriba, la cadena entre comillas'|'
debe reemplazarse por cualquier carácter, o cadena de caracteres, ..." Pero no puede usartr
para reemplazar un carácter con una cadena (de longitud> 1). (3) En tu último ejemplo, dices-e 's/\<old\>/new/' -e 's/\<old\>/w/' | tr '\000' '\n'\>/new
. Esto parece ser un error tipográfico para-e 's/\<old\>/new/' -e 's/\<old\>/new/' -e 's/\<old\>/new/' | tr '\000' '\n'
.Usando Awk
Los comandos awk se pueden usar para reemplazar las primeras N apariciones de la palabra con el reemplazo.
Los comandos solo reemplazarán si la palabra es una coincidencia completa.
En los ejemplos a continuación, estoy reemplazando las primeras
27
apariciones deold
connew
Usando sub
Reemplazar el campo manualmente
Realizar un chequeo antes
RESULTADOS
P.ej
a
fuente
$i
bit, ha sido editado, gracias :)Supongamos que desea reemplazar solo las primeras tres instancias de una cadena ...
nota: lo anterior probablemente no funcionará con comentarios incrustados
... o en mi caso de ejemplo, de un '1' ...
SALIDA:
Allí uso dos técnicas notables. En primer lugar, cada aparición de
1
una línea se reemplaza por\n1
. De esta manera, como hago los reemplazos recursivos a continuación, puedo estar seguro de no reemplazar la ocurrencia dos veces si mi cadena de reemplazo contiene mi cadena de reemplazo. Por ejemplo, si lo reemplazohe
conhey
él, aún funcionará.Hago esto como:
En segundo lugar, estoy contando los reemplazos agregando un personaje al
h
espacio antiguo para cada ocurrencia. Una vez que llegue a tres, no ocurrirán más. Si aplica esto a sus datos y cambia los\{3\}
reemplazos totales que desea y las/\n1/
direcciones a lo que quiera reemplazar, debe reemplazar solo los que desee.Solo hice todas las
-e
cosas para facilitar la lectura. POSIXly Podría escribirse así:Y con GNU
sed
:Recuerde también que
sed
está orientado a líneas: no se lee en todo el archivo y luego intenta volver a recorrerlo, como suele ser el caso en otros editores.sed
Es simple y eficiente. Dicho esto, a menudo es conveniente hacer algo como lo siguiente:Aquí hay una pequeña función de shell que lo agrupa en un comando simplemente ejecutado:
Entonces con eso puedo hacer:
...y obten...
...o...
...Llegar...
... o, para que coincida con su ejemplo (en un orden de magnitud menor) :
fuente
Una alternativa corta en Perl:
Cambie el valor de `$ n $ a su gusto.
Cómo funciona:
new
porold
(s/old/new/
) y siempre que se pueda, se incrementa la variable$i
(++$i
).1 while ...
) siempre y cuando haya realizado menos$n
sustituciones en total y puede realizar al menos una sustitución en esa línea.fuente
Use un bucle de concha y
ex
!Sí, es un poco tonto.
;)
Nota: Esto puede fallar si hay menos de 50 instancias
old
en el archivo. (No lo he probado). Si es así, dejaría el archivo sin modificar.Mejor aún, usa Vim.
Explicación:
fuente
Una solución simple pero no muy rápida es recorrer los comandos descritos en /programming/148451/how-to-use-sed-to-replace-only-the-first-occurrence-in-a -archivo
Este comando sed en particular probablemente solo funcione para GNU sed y si newword no es parte de oldword . Para sed no GNU, vea aquí cómo reemplazar solo el primer patrón en un archivo.
fuente
Con GNU
awk
puede establecer el separador de registrosRS
para la palabra que se reemplazará delimitada por límites de palabras. Entonces se trata de establecer el separador de registros en la salida a la palabra de reemplazo para los primerosk
registros mientras se conserva el separador de registros original para el restoO
fuente