Come faccio a stampare tutto tranne l'ennesima riga in sed?


9
  • Mi piacerebbe fare il complemento / "opposto" di

    sed 13q;d <file.txt
    

    Più in generale, è possibile fare questo tipo di complemento / inverso / opposto in sed? O solo per regex?

  • Come faccio a stampare tutte tranne la terza all'ultima riga ?. Questo richiede due tace il conteggio in avanti sed? O c'è un modo per farsi sedcontare da dietro?

Risposte:


12

Parte 1

dElimina semplicemente la tredicesima riga:

sed '13d' <file.txt

E un modo generale per fare il complemento di quanto sopra è:

sed '13!d' <file.txt

Parte 2

Perché può essere fatto:

sed -n ':a;${P;q};N;4,$D;ba' <file.txt

Nota che 4è uno in più del numero richiesto. Quindi se volessi l'ultima riga 10, questo sarebbe 11.

Test con seq:

$ seq 100 | sed -n ':a;${P;q};N;4,$D;ba'
98
$ 

Tentativo di spiegazione

:a        # define label a
${        # match the last line
    P     # print the first line of the pattern space
    q     # quit
}
N         # match all lines: append the next line to the pattern
4,${      # match the range of lines 4 to the end of the file
    D     # delete the first line of the pattern space
}
ba        # match all lines: jump back to label a 

La preziosa aggiunta di Glenn Jackman:

Quella era "solo l'ennesima riga". Ecco "all MA MA l'ennesima riga":

sed -n ':a;${s/^[^\n]*\n//;p;q};N;4,${P;D};ba'

funziona con GNU sed, la \nsequenza potrebbe non funzionare con altri sed .


Ho provato questo con BSD sed (OSX) e ho scoperto che non funzionava abbastanza nel modulo sopra. I problemi sembrano essere:

  1. ; usato per separare le linee sembra funzionare generalmente, ma non funziona dopo un'etichetta
  2. BSD sed sembra richiedere ;dopo l'ultimo comando in un {}gruppo di comandi a una riga , mentre GNU sed no
  3. \npuò essere generalmente utilizzato nell'espressione regolare, ma apparentemente non all'interno di []un'espressione tra parentesi. Quindi, per escludere le nuove righe, possiamo usare qualcosa di simile [[:alnum:][:punct:][:graph:][:blank:]], sebbene ciò possa escludere altri caratteri (in particolare altri caratteri di controllo).

Quindi questo è un tentativo di una versione più indipendente dalla piattaforma:

sed -n ':a
${s/^[[:alnum:][:punct:][:graph:][:blank:]]*\n//p;q;};N;4,${P;D;};ba'

Questo sembra funzionare sotto OSX e Ubuntu.


@jimmij Le altre risposte a domande correlate nella rete SE suggeriscono che una soluzione head/ tailè molto più lenta di una sedsoluzione. Grazie comunque.
isomorfismi,

3
@isomorphismes nessun programma può conoscere il numero di righe in un file a meno che non passi attraverso l'intero file. Non c'è modo di aggirare questo. L'unico modo per contare dal basso è invertire il file e contare dall'alto o analizzarlo due volte. Quindi la testa / coda saranno più veloci che mai.
Terdon

@isomorfismi ... perché sono ( head/ tail) ottimizzati per fare ciò che fanno.
peterph,

@isomorphismes - modificato con tutte le parti di cui hai bisogno
Digital Trauma

Bello! Ho dovuto cambiare la mia risposta, poiché in qualche modo mi aspettavo che fosse più complicato. :)
peterph,
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.