In che modo il comando sed '1! G; h; $! D' inverte il contenuto di un file?


20

La mia domanda è collegata alla sedsoluzione specifica data in questa risposta per questa domanda di inversione di grepping . La soluzione sed/ grepche non riesco a decifrare è la seguente:

sed '1!G;h;$!d' file

Qualcuno può per favore decifrare questo comando?

So per VI (M) che G indica l'ultima riga del file e che in sed un bang (!) Seguito da un indirizzo funziona un po 'come grep -vquello, per dire che non corrisponderà a quella linea. Ma nel complesso lo script sed inline sopra è oltre me.


3
... molto lentamente ...
mikeserv,

1
Come suggerisce mikeserv. Si noti che questa sedricetta complicata è un modo estremamente inefficiente (complessità O (n ^ 2/2)) per invertire le righe in un file. Sarebbe proibitivamente lento per i file con un numero elevato di righe. Per un'alternativa molto più efficiente all'inversione dell'ordine di linea, vedere tacdai coreutils GNU.
arielf

Risposte:


35

Ciò inverte il file riga per riga.

sed '$ d 1 G;!; h!' di file

Innanzitutto, sedha uno spazio di attesa e uno spazio modello . Dobbiamo distinguerli prima di concentrarci su quel comando specifico.

Quando sedlegge una nuova riga, viene caricata nello spazio del motivo. Pertanto, quello spazio viene sovrascritto ogni volta che viene elaborata una nuova riga. D'altra parte, lo spazio di attesa è coerente sull'intera elaborazione e i valori possono essere memorizzati lì per un uso successivo.


Al comando:

Ci sono 3 comandi in questa dichiarazione: 1!G, he$!d

  • 1!Gsignifica che il Gcomando viene eseguito su ogni riga tranne la prima (la !nega 1). Gsignifica aggiungere ciò che è nello spazio di attesa nello spazio del modello.

  • hsi applica a ogni riga. Esso copia lo spazio modello allo spazio attesa (e sovrascrive).

  • $!dsi applica a ogni riga tranne l'ultima ( $rappresenta l'ultima riga, la !nega). dè il comando per eliminare la linea (spazio del motivo).


  1. Ora, quando viene letta la prima riga, sedesegue il hcomando. La prima riga viene copiata nello spazio di attesa. Quindi viene eliminato, poiché corrisponde alla $!condizione. sedcontinua con la seconda riga.
  2. La seconda riga corrisponde alla condizione 1!(non è la prima riga), quindi lo spazio di attesa (che ha la prima riga) viene aggiunto allo spazio del pattern (che ha la seconda riga). Dopodiché, nello spazio del modello, ora c'è la seconda linea seguita dalla prima linea, delimitata da una nuova riga. Ora, si happlica il comando (come in ogni riga); tutto ciò che si trova nello spazio modello viene copiato nello spazio di attesa. Si $!dapplica la terza istruzione ( ): la linea viene eliminata dallo spazio modello.
  3. Il passaggio 2 è ora completato con tutte le righe. Passiamo all'ultima riga.
  4. Nell'ultima riga ( $) viene eseguita quasi tutta la fase 2, ma non la parte di eliminazione ( d). sed, se richiamato senza -n, stampa automaticamente lo spazio del motivo alla fine dell'elaborazione per ciascuna riga di input. Pertanto, quando non viene eliminato, viene stampato lo spazio del motivo. Ora contiene tutte le righe in ordine inverso .

1
@Geek No, il hcomando copia lo spazio del motivo nello spazio di attesa, che persiste fino alla sedfine. Dopo la fine dello script tutto viene cancellato, perché il binario è uscito.
caos,

2
Possiamo pensare allo spazio di attesa come ai registri di Vim? Sono anche numerati? O ce n'è solo uno?
Geek,

2
@Geek In sedc'è solo uno spazio di attesa. È come una variabile che può contenere qualcosa.
caos,

1
@ user1717828 Se la prima riga non venisse stampata, una volta elaborata. Dato che sed non viene invocato, -ndobbiamo eliminare ogni riga tranne l'ultima. All'ultima riga sed aggiunge tutto dallo spazio di attesa allo spazio del motivo. E poiché il dcomando non verrà eseguito, la riga viene stampata (questa riga contiene ora l'intero file invertito).
caos,

1
(1) La domanda secondaria / osservazione del PO (nel commento) è: "Quindi il hcomando sull'ultima riga è una specie di no-op." (Con enfasi aggiunta e leggermente parafrasato). Ha ragione; quando sedelabora l' ultima riga di input , Glegge lo spazio di trattenimento (per aggiungerlo allo spazio del motivo), quindi hcopia lo spazio del motivo nello spazio di trattenimento, a cui non viene mai più fatto riferimento . Potremmo anche dire sed 'G;$!h;$!d'o sed 'G;$!{h;d}'. (2) Potremmo evitare di usare ddicendo sed -n 'G;h;$p'.
Scott
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.