¿Cómo imprimir todas las líneas después de una coincidencia hasta el final del archivo?

48

El archivo de entrada1 es:

dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

Le doy al partido el patrón desde adentro other file(como dog 123 4335desde file2).

Coincido con el patrón de la línea dog 123 4335y después de imprimir todas las líneas sin una línea coincidente, mi salida es:

cat 13123 23424
deer 2131 213132
bear 2313 21313

Si solo se usa sin dirección de línea, solo se usa el patrón, por ejemplo, 1s ¿cómo hacer coincidir e imprimir las líneas?

loganaayahee
fuente
¿Puede otro archivo contener un solo patrón para buscar, o uno por línea, y comenzar a buscar en la línea que se encuentre primero en el archivo buscado?
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Respuestas:

27

Suponiendo que desea hacer coincidir la línea completa con su patrón, con GNU sed, esto funciona:

sed -n '/^dog 123 4335$/ { :a; n; p; ba; }' infile

Equivalente estándar:

sed -ne '/^dog 123 4335$/{:a' -e 'n;p;ba' -e '}' infile

Con la siguiente entrada ( infile):

cat 13123 23424 
deer 2131 213132
bear 2313 21313
dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

El resultado es:

cat 13123 23424 
deer 2131 213132
bear 2313 21313

Explicación:

  • /^dog 123 4335$/ busca el patrón deseado.
  • :a; n; p; ba;es un bucle que recupera una nueva línea desde input ( n), la imprime ( p) y vuelve a ramificarse para etiquetar a :a; ...; ba;.

Actualizar

Aquí hay una respuesta que se acerca más a sus necesidades, es decir, patrón en el archivo2, grepping del archivo1:

tail -n +$(( 1 + $(grep -m1 -n -f file2 file1 | cut -d: -f1) )) file1

El grep y el corte incrustados encuentran la primera línea que contiene un patrón del archivo2, este número de línea más uno se pasa a la cola, el más está allí para omitir la línea con el patrón.

Si desea comenzar desde el último partido en lugar del primer partido, sería:

tail -n +$(( 1 + $(grep -n -f file2 file1 | tail -n1 | cut -d: -f1) )) file1

Tenga en cuenta que no todas las versiones de tail admiten la notación más.

Thor
fuente
Este es el primer ejemplo de los comandos n y p en sed que he visto que no parece llevar sed demasiado lejos. Parece (de mis breves pruebas) que sed -n '/^dog 123 4335$/ { :a; p; n; ba; }' infile(con el p y n conmutado) incluye con éxito la línea que coincide también.
Josiah Yoder
26

Si tiene un archivo razonablemente corto grepsolo podría funcionar:

grep -A5000 -m1 -e 'dog 123 4335' animals.txt

5000 es solo mi suposición en "razonablemente corto", ya que grepencuentra la primera coincidencia y la genera junto con las siguientes 5000 líneas (el archivo no necesita tener tantos). Si no quieres el partido en sí, deberás cortarlo, por ejemplo

grep -A5000 -m1 -e 'dog 123 4335' animals.txt | tail -n+2


Si no desea la primera, pero la última coincidencia como delimitador, puede usar esto:

tac animals.txt | sed -e '/dog 123 4335/q' | tac

Esta línea lee animals.txten orden inverso a las líneas y emite hasta e incluyendo la línea con dog 123 4335y luego se invierte nuevamente para restaurar el orden correcto.

Nuevamente, si no necesita la coincidencia en el resultado, agregue cola. (También podría complicar la expresión sed para descartar su búfer antes de salir).

Aet3miirah
fuente
Según mi prueba, GNU grep 3.0 no genera más de 132 líneas en el contexto posterior (independientemente del valor especificado).
ruvim
22

En la práctica, probablemente usaría la respuesta de Aet3miirah la mayor parte del tiempo y la respuesta de alexey es maravillosa cuando quiero navegar a través de las líneas (también, también funciona con less). OTOH, realmente me gusta otro enfoque (que es una especie de respuesta inversa de Gilles :

sed -n '/dog 123 4335/,$p'

Cuando se llama con el -nindicador, sedya no imprime las líneas que procesa. Luego usamos un formulario de 2 direcciones que dice que se aplique un comando desde la línea que coincide /dog 123 4335/hasta el final del archivo (representado por $). El comando en cuestión es p, que imprime la línea actual. Entonces, esto significa "imprimir todas las líneas desde la que coincida /dog 123 4335/hasta el final".

brandizzi
fuente
3
Sin dogembargo, eso imprime la línea que no se desea aquí.
Stéphane Chazelas
1
Esta parece la mejor respuesta (y funciona para mi propio caso) pero también necesitaría ser adaptada para omitir la línea coincidente.
Pavel Šimerda
1
sed -n '/ perro 123 4335 /, $ p' | sed '1d' eliminará la línea del perro
Kemin Zhou
1
sed -n '/dog 123 4335/,$p' | tail -n +2eliminará el partido también
gilad mayani
15
sed -e '1,/dog 123 4335/d' file1

Si necesita leer el patrón de un archivo, sustitúyalo en el comando sed. Si el archivo contiene un patrón sed:

sed -e "1,/$(cat file2)/d" file1

Si el archivo contiene una cadena literal para buscar, cita todos los caracteres especiales. Supongo que el archivo contiene una sola línea.

sed -e "1,/$(sed 's/[][\\\/^$.*]/\\&/g' file2)/d" file1

Si desea que la coincidencia sea toda la línea, no solo una subcadena, ajuste el patrón ^…$.

sed -e "1,/^$(sed 's/[][\\\/^$.*]/\\&/g' file2)\$/d" file1
Gilles 'SO- deja de ser malvado'
fuente
66
Eso no funcionará si el patrón está en la primera línea. GNU sedtiene 0,/dog.../dpara eso.
Stéphane Chazelas
14

$ more +/"dog 123 4335" file1

alexey
fuente
44
También funciona con less.
brandizzi
3
inteligente en el terminal, pero en realidad no funciona si lo conecta a otra cosa como tac.
jcomeau_ictx
Lo estoy usando así, $ more + / "coincide con mis palabras" file1 >> file2
AMB
1
Tal vez +fue reemplazado por -pPOSIX 7: pubs.opengroup.org/onlinepubs/9699919799/utilities/more.html pero aún no se implementó en util-linux 2.20.1. Y esto también imprime skipping..y algunas nuevas líneas adicionales (para stderr, espero, por lo que podría estar bien).
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
tal vez las cosas han cambiado desde entonces? mi comentario tiene 3 upvotes por lo que puede haber sido relevante en el momento ...
jcomeau_ictx
11

Con awk:

awk 'BEGIN {getline pattern < "other file"}
   NR == 1, $0 ~ pattern {next}; {print}' < "input file"
Stéphane Chazelas
fuente
5

Una forma de usar awk:

awk 'NR==FNR{a[$0];next}f;($0 in a){f=1}'  file2 file1

donde file2 contiene sus patrones de búsqueda. Primero, todo el contenido del archivo2 se almacena en la matriz "a". Cuando se procesa el archivo1, cada línea se compara con la matriz y se imprime solo si no está presente.

Gurú
fuente
Creo que el OP quiere mostrar cada línea siguiendo el patrón.
Thor el
@Thor: gracias por señalarlo, lo actualicé ahora ...
Guru
Bien hecho :).
Thor
5

Si la entrada es un archivo regular que se puede buscar :

Con GNU grep:

{ grep  -xFm1 'dog 123 4335' >&2
  cat; } <infile 2>/dev/null >outfile

Con sed:

{ sed -n '/^dog 123 4335$/q'
  cat; } <infile >outfile

Un GNU grepllamado w / la -mopción dejará la entrada en la coincidencia, y dejará su entrada (posible) fd inmediatamente después del punto en que encontró su última coincidencia. Entonces, llamar a grepw / -m1encuentra la primera aparición de un patrón en un archivo, y deja el desplazamiento de entrada exactamente en el lugar correcto para catescribir todo después de la primera coincidencia del patrón en un archivo para stdout.

Incluso sin un GNU grep, puede hacer exactamente lo mismo con un POSIX compatible sed: cuando sed qse especifica, deja su desplazamiento de entrada justo donde lo hace. Sin sedembargo, GNU no cumple con los estándares de esta manera, por lo que lo anterior probablemente no funcionará con un GNU a sedmenos que lo llame con su -uinterruptor.

mikeserv
fuente
tenga en cuenta que la sedtransmisión compartida que se muestra aquí no es especialmente (aunque sí, el estándar al que se hace referencia específicamente ejemplifica sedcomo una utilidad así capaz) del flujo de trabajo de forma libre y condicionalmente cooperativo que se muestra. en particular, todas las utilidades estándar están diseñadas y especificadas para cooperar y compartir las posiciones del cursor de las secuencias de entrada sin que el siguiente lector falle en el procesamiento. grep -qdebería hacer esto; silenciosamente grepdebería regresar tan pronto como se encuentre una coincidencia en la entrada, y cualquier resto de entrada no debería, por norma, ser consumido por defecto.
mikeserv
4

Mi respuesta a la pregunta en el tema, sin almacenar el patrón en un segundo archivo. Aquí está mi archivo de prueba:

$ cat animals.txt 
cat 13123 23424 
deer 2131 213132
bear 2313 21313
dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

GNU sed:

 $ sed '0,/^dog 123 4335$/d' animals.txt 
 cat 13123 23424 
 deer 2131 213132
 bear 2313 21313

Perl:

$ perl -ne 'print unless 1.../^dog 123 4335$/' animals.txt
cat 13123 23424 
deer 2131 213132
bear 2313 21313

Variante de Perl con patrón en un archivo:

$ cat pattern.txt 
dog 123 4335
$ perl -ne 'BEGIN{chomp($p=(<STDIN>)[0])};print unless 1../$p/;' animals.txt < pattern.txt
cat 13123 23424 
deer 2131 213132
bear 2313 21313
jbgood
fuente
2

Wth ed:

ed -s file1 <<< '/dog 123 4335/+1,$p'

Esto envía un pcomando rint a ed en una cadena aquí; el comando de impresión está limitado en rango a uno después ( +1) de la dog 123 4335coincidencia hasta el final del archivo ( $).

Jeff Schaller
fuente
1

Si no le importa la creación de un archivo temporal y lo tiene csplitdisponible, esto funciona:

sh -c 'csplit -sf"$1_" "$1" "%^$(cat "$2")%+1" && cat "${1}_00"' sh file1 file2

Note file1es el archivo de entrada y file2es el archivo de patrón (como se indica en la pregunta).

La forma larga del comando anterior es:

sh -c 'csplit --quiet --prefix="$1_" "$1" "%^$(cat "$2")%+1" && cat "${1}_00"' sh file1 file2

es decir,

csplit --quiet --prefix="file1_" "file1" "%^$(cat "file2")%+1" && cat "file1_00"

csplitsin la prefixbandera de arriba crearía el archivo xx00(siendo el prefijo xxy el sufijo 00). Con la bandera de arriba crea el archivo file1_00. Sin la quietbandera, imprime el tamaño del archivo de salida (tamaño del archivo resultante).

YenForYang
fuente
0

Dado que awk no está expresamente rechazado, esta es mi oferta asumiendo que 'gato' es la pareja.

awk '$0 ~ /cat/ { vart = NR }{ arr[NR]=$0 } END { for (i = vart; i<=NR ; i++) print arr[i]  }' animals.txt
Tom
fuente
0

¿Cómo imprimir todas las líneas después de una coincidencia hasta el final del archivo?

Otra forma de decirlo es "cómo eliminar todas las líneas desde la primera hasta el partido (incluido)", y esto se puede sedescribir como:

sed -e '1,/MATCH PATTERN/d'
poige
fuente
1
El único problema es cuando el patrón está en la primera línea ...
don_crissti
1
¿Es esto diferente de unix.stackexchange.com/a/56517/32558 ?
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
Creo que necesitamos un comité aquí para decidir.
poige
1
@poige: nah, proporcionas la misma respuesta de manera menos exhaustiva
Thor
@don_crissti, ¿qué pasa sed -e '0,/MATCH PATTERN/d'entonces?
Velkan