Come eliminare da un file di testo, tutte le righe che contengono una stringa specifica?


Risposte:


2760

Per rimuovere la linea e stampare l'output sullo standard out:

sed '/pattern to match/d' ./infile

Per modificare direttamente il file - non funziona con BSD sed:

sed -i '/pattern to match/d' ./infile

Lo stesso, ma per BSD sed (Mac OS X e FreeBSD) - non funziona con GNU sed:

sed -i '' '/pattern to match/d' ./infile

Per modificare direttamente il file (e creare un backup) - funziona con BSD e GNU sed:

sed -i.bak '/pattern to match/d' ./infile

13
Grazie, ma non sembra cancellarlo dal file ma semplicemente stampare il contenuto del file di testo senza quella stringa.
Un'arancia meccanica

115
@A Clockwork: sì, è necessario reindirizzare l'output su un nuovo file con qualcosa di simile sed '/pattern to match/d' ./infile > ./newfileo se si desidera eseguire una modifica sul posto, è possibile aggiungere il -iflag a sed come in sed -i '/pattern to match/d' ./infile. Nota che la -ibandiera richiede GNU sed e non è portatile
SiegeX

16
Per alcuni sapori di sed; La bandiera "-i" di sed richiedeva un'estensione da fornire. (ad es. sed -i.backup '/pattern to match/d' ./infile) Mi hanno fatto capire con le modifiche sul posto.
avelis,

9
@SiegeX Meglio ancora, non applicare comandi simili seda tutti i file che non sono controllati dalla versione.
MatrixFrog,

84
Un'altra nota per gli utenti di Mac OS X: per qualche motivo, il flag -i richiede che venga passato un argomento, anche se è solo una stringa vuota, come sed -i '' '/pattern/d' ./infile.
geerlingguy,

631

Esistono molti altri modi per eliminare le righe con una stringa specifica oltre a sed:

AWK

awk '!/pattern/' file > temp && mv temp file

Rubino (1.9+)

ruby -i.bak -ne 'print if not /test/' file

Perl

perl -ni.bak -e "print unless /pattern/" file

Shell (bash 3.2 e successive)

while read -r line
do
  [[ ! $line =~ pattern ]] && echo "$line"
done <file > o
mv o file

GNU grep

grep -v "pattern" file > temp && mv temp file

E ovviamente sed(la stampa del contrario è più veloce della cancellazione effettiva):

sed -n '/pattern/!p' file

4
come eliminare una linea particolare con un motivo e anche la linea immediatamente sopra di essa? Ho una multa con migliaia di tali righe tra dati diversi.
oortcloud_domicile il

1
Su OS / X, la variazione della shell non conserva gli spazi iniziali, ma la variazione grep -v ha funzionato bene per me.
Paul Beusterien,

13
l' sedesempio ha un comportamento diverso, solo greps! dovrebbe essere qualcosa di simile sed -n -i '/pattern/!p' file.
Caesarsol,

8
La versione grep non funziona quando ogni riga corrisponde al modello. Meglio fare: grep -v "pattern" file > temp; mv temp filequesto potrebbe applicarsi ad alcuni degli altri esempi a seconda del valore restituito.
Chris Maes,

1
"stampare l'inverso è più veloce della cancellazione effettiva" - Non sulla mia macchina (MacBook Air 2012, OS X 10.13.2). Creare il file: seq -f %f 10000000 >foo.txt. sed d: time sed -i '' '/6543210/d' foo.txt0m9.294s reali. sed! p: time sed -i '' -n '/6543210/!p' foo.txt0m13.671s reali. (Per file più piccoli, la differenza è maggiore.)
jcsahnwaldt dice GoFundMonica

252

Puoi usare sed per sostituire le linee presenti in un file. Tuttavia, sembra essere molto più lento rispetto all'uso di grep per l'inverso in un secondo file e quindi spostando il secondo file sull'originale.

per esempio

sed -i '/pattern/d' filename      

o

grep -v "pattern" filename > filename2; mv filename2 filename

Il primo comando richiede comunque 3 volte più tempo sulla mia macchina.


19
Votare anche la tua risposta, solo perché hai provato un confronto delle prestazioni!
anuragw,

4
+1 per l'offerta dell'opzione per sovrascrivere il file corrente con la riga grep.
Rhyuk,

2
La seconda soluzione 'grep' è anche migliore per file di grandi dimensioni
simoes

3
Sono curioso di sapere quale sarebbe la differenza di prestazione se fossesed '/pattern/d' filename > filename2; mv filename2 filename
Pete

9
(usando ubuntu / usr / share / dict / words) grep e mv: 0.010s | sed sul posto: 0.197s | sed e mv: 0.031s
ReactiveRaven

77

Il modo semplice per farlo, con GNU sed:

sed --in-place '/some string here/d' yourfile

56
Un suggerimento utile per gli altri che si imbattono in questo thread di domande e risposte e non hanno familiarità con gli script di shell: le opzioni brevi vanno bene per gli usi una tantum sulla riga di comando, ma le opzioni lunghe dovrebbero essere preferite negli script poiché sono più leggibili.
Dennis,

3
+1 per la bandiera --in place. Devo testarlo su file protetti da autorizzazioni. (devi fare un po 'di pulizia da parte degli utenti.)
Bee Kay,

8
Nota che l'opzione lunga è disponibile solo su GNU sed. Gli utenti Mac e BSD dovranno installare gsed per farlo in questo modo.
Matt,

Un altro consiglio: se il tuo regex non sembra corrispondere, prova l' -ropzione (o -E, a seconda della versione). Ciò consente l'utilizzo di metacaratteri regex +, ?, {...}e (...).
rjh

Questa è la risposta corretta quando il disco non ha più spazio e non è possibile copiare il testo in un altro file. Questo comando fa ciò che è stato messo in discussione?
ferreirabraga,

38

Puoi prendere in considerazione l'utilizzo ex(che è un editor standard basato su comandi Unix):

ex +g/match/d -cwq file

dove:

  • +esegue il comando Ex dato ( man ex), lo stesso di quello -cche esegue wq(scrivi ed esci)
  • g/match/d- Ex comando per cancellare le righe con dato match, vedi: Potenza di g

L'esempio sopra è un metodo conforme a POSIX per la modifica sul posto di un file come da questo post nelle specifiche exUnix.SE e POSIX per .


La differenza sedè che:

sedè un S tream ED itor, non un editor di file. BashFAQ

A meno che non ti piaccia il codice non portabile, I / O overhead e alcuni altri effetti collaterali negativi. Quindi sostanzialmente alcuni parametri (come sul posto / -i) sono estensioni di FreeBSD non standard e potrebbero non essere disponibili su altri sistemi operativi.


5
è fantastico ... quando lo faccio man exmi dà l'uomo per vim, sembra che faccia exparte di Vim ... se ho capito bene ciò significa che la sintassi del modello per matchè vimregex.com che è simile ma diversa dai sapori POSIX e PCRE?
Anentropico,

1
:g è un comando conforme a POSIX con alcune lievi differenze . Presumo che PCRE fosse basato su questo.
Kenorb,

16

Stavo lottando con questo su Mac. Inoltre, dovevo farlo usando la sostituzione variabile.

Quindi ho usato:

sed -i '' "/$pattern/d" $file

dove $fileè il file in cui è necessaria la cancellazione e$pattern è il modello da abbinare per l'eliminazione.

Ho scelto il ''da questo commento .

La cosa da notare qui è l'uso di doppi apici in "/$pattern/d". La variabile non funzionerà quando utilizziamo virgolette singole.


3
Il Mac sedrichiede un parametro dopo -i, quindi se non si desidera un backup, è comunque necessario aggiungere una stringa vuota:-i ''
wisbucky

Per uso shell sed -i "/$pattern/d" $file. La ringrazio per la risposta.
ashwaqar,

14

Ho fatto un piccolo benchmark con un file che contiene circa 345000 righe. La strada grepsembra essere circa 15 volte più veloce del sedmetodo in questo caso.

Ho provato sia con che senza l'impostazione LC_ALL = C, non sembra cambiare significativamente i tempi. La stringa di ricerca (CDGA_00004.pdbqt.gz.tar) si trova da qualche parte nel mezzo del file.

Ecco i comandi e i tempi:

time sed -i "/CDGA_00004.pdbqt.gz.tar/d" /tmp/input.txt

real    0m0.711s
user    0m0.179s
sys     0m0.530s

time perl -ni -e 'print unless /CDGA_00004.pdbqt.gz.tar/' /tmp/input.txt

real    0m0.105s
user    0m0.088s
sys     0m0.016s

time (grep -v CDGA_00004.pdbqt.gz.tar /tmp/input.txt > /tmp/input.tmp; mv /tmp/input.tmp /tmp/input.txt )

real    0m0.046s
user    0m0.014s
sys     0m0.019s

su quale piattaforma sei? Quali versioni di sed / perl / grep usi?
hagello,

La piattaforma che utilizzo è Linux (Gentoo). La versione sed è GNU sed v 4.2.2, la versione perl perl 5 (non posso dire quale revisione ho usato al momento del test) e grep (GNU) è la versione 3.0.
Jadzia,

14

Puoi anche usare questo:

 grep -v 'pattern' filename

Qui -vverrà stampato solo diverso dal modello (ciò significa invertire la corrispondenza).


Come posso eliminare le righe in una directory che contiene una stringa specifica
namannimmo

13

Per ottenere un risultato sul posto con grepte puoi fare questo:

echo "$(grep -v "pattern" filename)" >filename

4
Questo è buono solo per la bashshell o simili (no tcsh).
esci il


4
perl -i    -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3

Il primo comando modifica i file sul posto (-i).

Il secondo comando fa la stessa cosa ma mantiene una copia o un backup dei file originali aggiungendo .bk ai nomi dei file (.bk può essere modificato in qualsiasi cosa).


2

echo -e "/thing_to_delete\ndd\033:x\n" | vim file_to_edit.txt


2

Nel caso in cui qualcuno voglia farlo per esatte corrispondenze di stringhe, puoi usare la -wbandiera in grep - w per intero. Cioè, ad esempio, se si desidera eliminare le righe che hanno il numero 11, ma mantenere le righe con il numero 111:

-bash-4.1$ head file
1
11
111

-bash-4.1$ grep -v "11" file
1

-bash-4.1$ grep -w -v "11" file
1
111

Funziona anche con la -fbandiera se si desidera escludere più modelli esatti contemporaneamente. Se "blacklist" è un file con diversi motivi su ciascuna riga che si desidera eliminare da "file":

grep -w -v -f blacklist file

Un po 'fuorviante. -w, --word-regexp Select only those lines containing matches that form whole words.vs.-x, --line-regexp Select only those matches that exactly match the whole line. For a regular expression pattern, this is like parenthesizing the pattern and then surrounding it with ^ and $.
Sai,


0

per mostrare il testo trattato nella console

cat filename | sed '/text to remove/d' 

per salvare il testo trattato in un file

cat filename | sed '/text to remove/d' > newfile

per aggiungere informazioni di testo trattate a un file esistente

cat filename | sed '/text to remove/d' >> newfile

per trattare il testo già trattato, in questo caso rimuovere più righe di ciò che è stato rimosso

cat filename | sed '/text to remove/d' | sed '/remove this too/d' | more

il | moremostrerà testo in blocchi di una pagina alla volta.


0

Puoi usare il buon vecchio edper modificare un file in modo simile alla risposta che usa ex. La grande differenza in questo caso è che edaccetta i suoi comandi tramite input standard, non come argomenti della riga di comando come expuò. Quando lo si utilizza in uno script, il modo normale per adattarlo è utilizzare printfper inoltrare i comandi ad esso:

printf "%s\n" "g/pattern/d" w | ed -s filename

o con una eredità:

ed -s filename <<EOF
g/pattern/d
w
EOF
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.