Eliminare numeri di riga specifici da un file di testo usando sed?


Risposte:


374

Se si desidera eliminare le righe da 5 a 10 e 12:

sed -e '5,10d;12d' file

Questo stamperà i risultati sullo schermo. Se si desidera salvare i risultati nello stesso file:

sed -i.bak -e '5,10d;12d' file

Questo eseguirà il backup del file file.bake cancellerà le righe indicate.

Nota: i numeri di riga iniziano da 1. La prima riga del file è 1, non 0.


32
Non tutti gli unix hanno gnu sed con "-i". Non commettere l'errore di tornare a "sed cmd file> file", che cancellerà il tuo file.
pra

4
cosa succede se volessi cancellare la 5a riga fino all'ultima riga?
Jürgen Paul,

14
@WearetheWorldsed -e '5,$d' file
Brian Campbell,

1
@BrianCampbell Cosa devo fare per eliminare solo una riga particolare ??
Kanagavelu Sugumar

14
@KanagaveluSugumar sed -e '5d' file. La sintassi è <address><command>; dove <address>può essere una linea singola 5o un intervallo di linee come 5,10, e il comando delimina la linea o le linee indicate. Gli indirizzi possono anche essere espressioni regolari o il simbolo del dollaro che $indica l'ultima riga del file.
Brian Campbell,

50

È possibile eliminare una determinata riga singola con il suo numero di riga da

sed -i '33d' file

Ciò eliminerà la riga sul numero di 33 righe e salverà il file aggiornato.


1
Nel mio caso "sed" ha rimosso una linea sbagliata. Quindi io uso questo approccio: sed -i '0,/<TARGET>/{/<NEW_VALUE>/d;}' '<SOME_FILE_NAME>'. Grazie!
Eduardo Lucio,

Lo stesso qui, ho scritto un ciclo e stranamente alcuni file hanno perso la riga corretta ma alcuni file hanno perso anche un'altra riga, non ho idea di cosa sia andato storto. (GNU / Linux bash4.2) il comando awk di seguito ha funzionato perfettamente in loop
FatihSarigol,

Fai molta attenzione a usare sort -r se stai cancellando da un elenco di righe, altrimenti il ​​tuo primo sed cambierà i numeri di riga di tutto il resto! ...
Konchog

Per commenti sulle righe errate che vengono eliminate in un ciclo: assicurati di iniziare con il numero di riga più grande, altrimenti ogni riga eliminata compenserà la numerazione delle righe ...
Skippy le Grand Gourou

25

e anche imbarazzato

awk 'NR!~/^(5|10|25)$/' file

2
NB: Quella linea awk ha funzionato in modo più affidabile per me rispetto alla variante sed (tra OS-X e Ubuntu Linux)
Jay Taylor,

3
Si noti che ciò non elimina nulla nel file. Stampa semplicemente il file senza queste righe su stdout. Quindi è anche necessario reindirizzare l'output su un file temporaneo, quindi spostare il file temporaneo per sostituire l'originale.
lunedì


6

Questo è molto spesso un sintomo di un antipasto. Lo strumento che ha prodotto i numeri di riga può essere sostituito con uno che elimina immediatamente le righe. Per esempio;

grep -nh error logfile | cut -d: -f1 | deletelines logfile

(dov'è deletelinesl'utilità che stai immaginando di aver bisogno) è la stessa di

grep -v error logfile

Detto questo, se ti trovi in ​​una situazione in cui hai davvero bisogno di eseguire questa attività, puoi generare un semplice sedscript dal file dei numeri di riga. Con umorismo (ma forse un po 'di confusione) puoi farlo sed.

sed 's%$%d%' linenumbers

Questo accetta un file di numeri di riga, uno per riga, e produce, sullo standard output, gli stessi numeri di riga con l' daggiunta dopo ciascuno. Questo è uno sedscript valido , che possiamo salvare in un file o (su alcune piattaforme) reindirizzare a un'altra sedistanza:

sed 's%$%d%' linenumbers | sed -f - logfile

Su alcune piattaforme, sed -fnon capisce l'argomento opzione -per indicare l'input standard, quindi devi reindirizzare lo script su un file temporaneo e ripulirlo quando hai finito, o forse sostituire il trattino solitario con /dev/stdino /proc/$pid/fd/1se il tuo sistema operativo (o shell ) ha questo.

Come sempre, è possibile aggiungere -iprima -fdell'opzione per sedmodificare il file di destinazione in luogo, invece di produrre il risultato sull'output standard. Su piattaforme * BSDish (incluso OSX) è necessario fornire anche un argomento esplicito -i; un linguaggio comune è quello di fornire un argomento vuoto; -i ''.


Non sono del tutto d'accordo con "sintomo di un antipasto". I tipi di file basati su markup (ad es. XML o JSON) richiedono linee specifiche alla fine per essere file validi. In tal caso, è spesso l'approccio più ragionevole per rimuovere quelle linee, inserire nel file ciò che si desidera aggiungere e quindi aggiungere nuovamente quelle linee, perché mettere le linee tra di loro immediatamente può essere molto più sforzo e va contro il potenziale desiderio di evitare strumenti extra come sed il più possibile.
Egor Hans,

Non capisco bene quale tipo di scenario stai immaginando. Ci sono scenari in cui questo è un approccio legittimo, ma la stragrande maggioranza dei casi che ho visto sono neofiti che fanno più o meno esattamente ciò che dimostra il mio primo esempio. (Forse provengono da un linguaggio di basso livello e sono abituati a dividere il loro problema oltre il livello molecolare, perché devi farlo in asm o C.)
tripleee

Rimuovere elementi per numero di riga da XML o JSON sembra estremamente fragile, se non addirittura pericoloso.
Tripleee

Ciò che intendo sostanzialmente con questo, è che come creatore di un tale file, sai cosa deve essere alla fine del documento (ovvero l'insieme di parentesi quadre / parentesi quadre nelle ultime poche righe per JSON, o l'esatto tag di chiusura per XML). Consapevole di ciò, l'approccio più semplice per estendere tale documento è 1) rimuovere le ultime righe, 2) aggiungere il nuovo contenuto, 3) aggiungere nuovamente le ultime righe. In questo modo, il documento può essere valido sia prima che dopo che è stato esteso, senza la necessità di trovare un modo per aggiungere righe a metà documento.
Egor Hans,

1
Finora questa è l'unica risposta con una soluzione appropriata per un gran numero di righe (cioè fornite da un file). E anche la prefazione ha un senso. Merita più voti. A proposito, se si desidera stampare le linee anziché eliminarle, utilizzare pinvece di d, insieme all'opzione -n(non funzionerà senza -ne !dnon funzionerà neanche).
Skippy le Grand Gourou,

2

Vorrei proporre una generalizzazione con awk.

Quando il file viene creato da blocchi di dimensioni fisse e le righe da eliminare vengono ripetute per ciascun blocco, awk può funzionare bene in questo modo

awk '{nl=((NR-1)%2000)+1; if ( (nl<714) || ((nl>1025)&&(nl<1029)) ) print  $0}'
 OriginFile.dat > MyOutputCuttedFile.dat

In questo esempio la dimensione del blocco è 2000 e voglio stampare le linee [1..713] e [1026..1029].

  • NR è la variabile utilizzata da awk per memorizzare il numero di riga corrente.
  • % fornisce il resto (o modulo) della divisione di due numeri interi;
  • nl=((NR-1)%BLOCKSIZE)+1Qui scriviamo nella variabile nl il numero di riga all'interno del blocco corrente. (vedi sotto)
  • ||e &&sono l'operatore logico OR e AND .
  • print $0 scrive la riga completa

Why ((NR-1)%BLOCKSIZE)+1:
(NR-1) We need a shift of one because 1%3=1, 2%3=2, but 3%3=0.
  +1   We add again 1 because we want to restore the desired order.

+-----+------+----------+------------+
| NR  | NR%3 | (NR-1)%3 | (NR-1)%3+1 |
+-----+------+----------+------------+
|  1  |  1   |    0     |     1      |
|  2  |  2   |    1     |     2      |
|  3  |  0   |    2     |     3      |
|  4  |  1   |    0     |     1      |
+-----+------+----------+------------+


2
Ammiro il modo in cui vivi fino al tuo nome che induce alla follia.
Jukka Dahlbom,
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.