Come stampare tutte le righe dopo una corrispondenza fino alla fine del file?


48

Il file di input1 è:

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

Do alla corrispondenza il modello da in other file(come dog 123 4335da file2).

Corrispondo al motivo della linea è dog 123 4335e dopo aver stampato tutte le linee senza linea di corrispondenza il mio output è:

cat 13123 23424
deer 2131 213132
bear 2313 21313

Se usi solo senza indirizzo di linea usa solo il modello, ad esempio 1s come abbinare e stampare le linee?


Un altro file può contenere solo un singolo modello da cercare, o uno per riga, e iniziare a cercare la riga che si trova per prima nel file cercato?
Ciro Santilli 14 改造 中心 法轮功 六四 事件

Risposte:


27

Supponendo che tu voglia abbinare l'intera linea al tuo modello, con GNU sed, questo funziona:

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

Equivalente standard:

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

Con il seguente input ( infile):

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

L'output è:

cat 13123 23424 
deer 2131 213132
bear 2313 21313

Spiegazione:

  • /^dog 123 4335$/ cerca il modello desiderato.
  • :a; n; p; ba;è un ciclo che recupera una nuova riga da input ( n), la stampa ( p) e si ramifica per etichettare a :a; ...; ba;.

Aggiornare

Ecco una risposta che si avvicina alle tue esigenze, ovvero modello in file2, grepping da file1:

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

Il grep incorporato e il taglio trovano la prima riga contenente un modello da file2, questo numero di riga più uno viene passato alla coda, il più è lì per saltare la linea con il modello.

Se vuoi iniziare dall'ultima partita invece della prima partita sarebbe:

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

Nota che non tutte le versioni di coda supportano la notazione più.


Questo è il primo esempio dei comandi n e p in sed che ho visto che non mi sembra di andare troppo lontano in sed. Sembra (dai miei brevi test) che sed -n '/^dog 123 4335$/ { :a; p; n; ba; }' infile(con p e n commutati) includa con successo anche la linea corrispondente.
Josiah Yoder,

26

Se hai un file ragionevolmente breve grepda solo potrebbe funzionare:

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

5000 è solo una mia ipotesi su "ragionevolmente breve", poiché greptrova la prima corrispondenza e la restituisce insieme alle successive 5000 righe (il file non ha bisogno di avere così tante). Se non si desidera la corrispondenza stessa, è necessario interromperla, ad es

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


Se non vuoi il primo, ma l'ultimo match come delimitatore, puoi usare questo:

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

Questa riga legge animals.txtin ordine inverso rispetto alle righe e produce fino alla linea compresa, inclusa, dog 123 4335e quindi inverte nuovamente per ripristinare l'ordine corretto.

Ancora una volta, se non hai bisogno della corrispondenza nel risultato, aggiungi la coda. (Potresti anche complicare l'espressione sed per scartare il suo buffer prima di uscire.)


Secondo il mio test, GNU grep 3.0 non genera più di 132 righe in post-contesto (indipendentemente dal valore specificato).
ruvim,

22

In pratica probabilmente userò la risposta di Aet3miirah la maggior parte delle volte e la risposta di alexey è meravigliosa quando voglio navigare attraverso le linee (inoltre, funziona anche con less). OTOH, mi piace molto un altro approccio (che è un po 'la risposta inversa di Gilles :

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

Quando viene chiamato con il -nflag, sednon stampa più le linee che elabora di default. Quindi usiamo un modulo a 2 indirizzi che dice di applicare un comando dalla corrispondenza della riga /dog 123 4335/fino alla fine del file (rappresentato da $). Il comando in questione è p, che stampa la riga corrente. Quindi, questo significa "stampa tutte le righe da quella corrispondente /dog 123 4335/fino alla fine".


3
Ciò stampa la doglinea anche se non è voluto qui.
Stéphane Chazelas,

1
Questa sembra la risposta migliore (e funziona per il mio caso) ma dovrebbe essere adattata per saltare anche la linea corrispondente.
Pavel Šimerda,

1
sed -n '/ dog 123 4335 /, $ p' | sed '1d' rimuoverà la linea del cane
Kemin Zhou,

1
sed -n '/dog 123 4335/,$p' | tail -n +2rimuoverà anche la partita
gilad mayani,

15
sed -e '1,/dog 123 4335/d' file1

Se è necessario leggere il modello da un file, sostituirlo nel comando sed. Se il file contiene un modello sed:

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

Se il file contiene una stringa letterale da cercare, citare tutti i caratteri speciali. Presumo che il file contenga una sola riga.

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

Se si desidera che la corrispondenza sia l'intera riga, non solo una sottostringa, avvolgere il motivo ^…$.

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

6
Ciò non funzionerà se il modello si trova sulla prima riga. GNU sedha 0,/dog.../dper questo.
Stéphane Chazelas,

14

$ more +/"dog 123 4335" file1


4
Funziona anche con less.
brandizzi,

3
intelligente sul terminale, ma in realtà non funziona se lo installi in qualcos'altro tac.
jcomeau_ictx,

lo sto usando in questo modo, $ more + / "abbina le mie parole" file1 >> file2
AMB

1
Forse è +stato sostituito da -pPOSIX 7: pubs.opengroup.org/onlinepubs/9699919799/utilities/more.html ma non ancora implementato in util-linux 2.20.1. E anche questo stampa skipping..e alcune nuove righe extra (a stderr mi aspetto, quindi potrebbe andare bene).
Ciro Santilli 14 改造 中心 法轮功 六四 事件

forse le cose sono cambiate da allora? il mio commento ha ottenuto 3 voti, quindi potrebbe essere stato rilevante al momento ...
jcomeau_ictx

11

Con awk:

awk 'BEGIN {getline pattern < "other file"}
   NR == 1, $0 ~ pattern {next}; {print}' < "input file"

5

Un modo usando awk:

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

dove file2 contiene i tuoi schemi di ricerca. Innanzitutto, tutti i contenuti di file2 sono memorizzati nell'array "a". Quando il file1 viene elaborato, ogni riga viene verificata rispetto all'array e stampata solo se non è presente.


Penso che l'OP voglia emettere ogni linea seguendo lo schema.
Thor,

@Thor: grazie per averlo sottolineato, aggiornato ora ...
Guru

Ben fatto :).
Thor,

5

Se l'input è un file normale ricercabile :

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

Una GNU grepchiamata w / l' -mopzione uscirà dall'input alla partita - e lascerà il suo input (cercabile) fd immediatamente dopo il punto in cui ha trovato la sua ultima corrispondenza. Quindi chiamando grepw / -m1trova la prima occorrenza di un pattern in un file e lascia l'offset di input esattamente nel posto giusto per catscrivere su stdout tutto ciò che segue la prima corrispondenza del pattern in un file.

Anche senza una GNU greppuoi fare esattamente la stessa cosa con un POSIX compatibile sed- quando lo sed qfai è specificato per lasciare il suo offset di input proprio dove lo fa. GNU sednon è conforme agli standard in questo modo, tuttavia, e quindi quanto sopra probabilmente non funzionerà con una GNU a sedmeno che tu non lo chiami con il suo -uinterruttore.


si noti che la sedcondivisione del flusso qui dimostrata non è particolarmente (sebbene, sì, lo standard a cui si fa riferimento in modo esemplificativo sedcome un'utilità così capace) del flusso di lavoro in forma libera e condizionatamente cooperativo mostrato. in particolare, tutte le utility standard sono pensate e specificate per cooperare e condividere così le posizioni del cursore dei flussi di input senza fallire l'elaborazione del lettore successivo. grep -qdovrebbe fare questo; grepdovrebbe tornare silenziosamente non appena viene trovata una corrispondenza nell'input e qualsiasi residuo dell'input non dovrebbe, per impostazione predefinita, essere consumato per impostazione predefinita.
Mikeserv,

4

La mia risposta per la domanda nell'argomento, senza memorizzare il modello in un secondo file. Ecco il mio file di test:

$ 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 Perl con motivo in un file:

$ 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

2

Con ed:

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

Questo invia un pcomando rint a ed in una stringa qui; il comando di stampa è limitato nell'intervallo a uno dopo ( +1) la dog 123 4335corrispondenza fino alla fine del file ( $).


1

Se non ti dispiace la creazione di un file temporaneo e hai a csplitdisposizione, questo funziona:

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

Nota file1è il file di input ed file2è il file di pattern (come indicato nella domanda).

La forma lunga del comando sopra è:

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

vale a dire,

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

csplitsenza il prefixflag sopra creerebbe il file xx00(essendo prefisso xxe suffisso 00). Con la bandiera sopra crea il file file1_00. Senza il quietflag, stampa la dimensione del file di output (dimensione del file risultante).


0

Poiché awk non è espressamente vietato, ecco la mia offerta supponendo che "cat" sia la partita.

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

0

Come stampare tutte le righe dopo una corrispondenza fino alla fine del file?

Un altro modo per dirlo è "come eliminare tutte le righe dalla prima fino alla corrispondenza (incluso)", e questo può essere sedscritto come:

sed -e '1,/MATCH PATTERN/d'

1
L'unico problema è quando il modello è sulla prima riga ...
don_crissti


Immagino che abbiamo bisogno di un comitato qui per decidere.
poige

1
@poige: nah, fornisci la stessa risposta in modo meno completo
Thor,

@don_crissti, sed -e '0,/MATCH PATTERN/d'allora?
Velkan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.