
Tengo el siguiente archivo de texto.
banana
apple
juice
mango
something
Estoy buscando patrón juice
y quiero encontrar la segunda línea de ese patrón coincidente en orden inverso (es decir, 2 líneas encima del patrón coincidente) y reemplazarla con coconut
.
Rendimiento esperado:
coconut
apple
juice
mango
something
Intenté seguir, pero simplemente elimina las dos líneas anteriores y no la que estoy buscando exactamente.
tac foo.txt |sed '/juice/I,+2 d' |tac
mango
something
Creo que modificar el script anterior funcionaría, pero no estoy seguro.
Nota: La coincidencia no volverá a ocurrir y no es necesario que sea una coincidencia exacta (es decir, la coincidencia también se puede encontrar en una línea larga). La coincidencia debe distinguir entre mayúsculas y minúsculas.
Respuesta1
Si ed
está bien, necesita editar un archivo, no una secuencia, y solo hay uno juice
:
$ more <<-EOF | ed -s ./tmp.txt
/juice/
-2
c
coconut
.
w
q
EOF
$
Encuentra la línea, sube dos líneas, c
cuelga,
w
rito y q
uit.
Una variación aún más compacta, sugerida por @d-ben-knoble en los comentarios:
$ printf '%s\n' '/^juice$/-2s/.*/coconut/' w q | ed -s ./tmp.txt
Respuesta2
Siguiendo su planteamiento,
tac file|sed '/juice/{n;n;s/.*/coconut/}'|tac
/juice/
coincide con una línea conjuice
.n;n;
imprime la línea actual y la siguiente.s/.*/coconut/
hace la sustitución.
Aparentemente tienes GNU sed, por lo que también puedes usarlo -z
para guardar todo el archivo en la memoria y editar directamente la línea dos arriba de jugo,
sed -rz 's/[^\n]*(\n[^\n]*\n[^\n]*juice)/coconut\1/' file
[^\n]
significa "no una nueva línea" y el paréntesis ()
captura el grupo reproducido por la \1
referencia inversa.
Respuesta3
$ tac file | awk 'c&&!(--c){$0="coconut"} /juice/{c=2} 1' | tac
coconut
apple
juice
mango
something
Respuesta4
Aquí hay otro awk
enfoque, esta vez un método de doble paso:
awk 'NR==FNR&&/juice/{m=FNR} NR>FNR&&FNR==m-2{$0="coconut"} (NR>FNR)' file file
- Especificamos el archivodos vecescomo argumentos de línea de comandos, para que se procese dos veces.
- En la primera pasada (donde
FNR
, el contador de líneas por archivo, es igual aNR
, el contador de líneas global), simplemente identificamos en qué líneajuice
ocurre el patrón de búsqueda y lo almacenamos en una variablem
. - En la segunda pasada, configuramos el número de línea
m-2
para el texto de reemplazococonut
. - Como regla general, imprimimos las líneas que incluyen cualquier modificación, pero solo en la segunda pasada (donde la condición
NR>FNR
se evalúa como "verdadera").
Si tiene GNU awk
(algunas otras awk
implementaciones también lo admiten), puede acelerar un poco el proceso abortando el primer paso tan pronto como se encuentre la coincidencia usando el nextfile
comando:
awk 'NR==FNR&&/juice/{m=FNR;nextfile} NR>FNR&&FNR==m-2{$0="coconut"} (NR>FNR)' file file