Come userei sed per cancellare tutte le righe di un file di testo che contengono una stringa specifica?
Come userei sed per cancellare tutte le righe di un file di testo che contengono una stringa specifica?
Risposte:
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
sed '/pattern to match/d' ./infile > ./newfile
o se si desidera eseguire una modifica sul posto, è possibile aggiungere il -i
flag a sed come in sed -i '/pattern to match/d' ./infile
. Nota che la -i
bandiera richiede GNU sed e non è portatile
sed -i.backup '/pattern to match/d' ./infile
) Mi hanno fatto capire con le modifiche sul posto.
sed
a tutti i file che non sono controllati dalla versione.
sed -i '' '/pattern/d' ./infile
.
Esistono molti altri modi per eliminare le righe con una stringa specifica oltre a sed
:
awk '!/pattern/' file > temp && mv temp file
ruby -i.bak -ne 'print if not /test/' file
perl -ni.bak -e "print unless /pattern/" file
while read -r line
do
[[ ! $line =~ pattern ]] && echo "$line"
done <file > o
mv o file
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
sed
esempio ha un comportamento diverso, solo greps! dovrebbe essere qualcosa di simile sed -n -i '/pattern/!p' file
.
grep -v "pattern" file > temp; mv temp file
questo potrebbe applicarsi ad alcuni degli altri esempi a seconda del valore restituito.
seq -f %f 10000000 >foo.txt
. sed d: time sed -i '' '/6543210/d' foo.txt
0m9.294s reali. sed! p: time sed -i '' -n '/6543210/!p' foo.txt
0m13.671s reali. (Per file più piccoli, la differenza è maggiore.)
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.
sed '/pattern/d' filename > filename2; mv filename2 filename
Il modo semplice per farlo, con GNU sed
:
sed --in-place '/some string here/d' yourfile
-r
opzione (o -E
, a seconda della versione). Ciò consente l'utilizzo di metacaratteri regex +
, ?
, {...}
e (...)
.
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 -c
che esegue wq
(scrivi ed esci)g/match/d
- Ex comando per cancellare le righe con dato match
, vedi: Potenza di gL'esempio sopra è un metodo conforme a POSIX per la modifica sul posto di un file come da questo post nelle specifiche ex
Unix.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.
man ex
mi dà l'uomo per vim
, sembra che faccia ex
parte 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?
:g
è un comando conforme a POSIX con alcune lievi differenze . Presumo che PCRE fosse basato su questo.
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.
sed
richiede un parametro dopo -i
, quindi se non si desidera un backup, è comunque necessario aggiungere una stringa vuota:-i ''
sed -i "/$pattern/d" $file
. La ringrazio per la risposta.
Ho fatto un piccolo benchmark con un file che contiene circa 345000 righe. La strada grep
sembra essere circa 15 volte più veloce del sed
metodo 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
Puoi anche usare questo:
grep -v 'pattern' filename
Qui -v
verrà stampato solo diverso dal modello (ciò significa invertire la corrispondenza).
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).
Nel caso in cui qualcuno voglia farlo per esatte corrispondenze di stringhe, puoi usare la -w
bandiera 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 -f
bandiera 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
-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 $.
cat filename | grep -v "pattern" > filename.1
mv filename.1 filename
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 | more
mostrerà testo in blocchi di una pagina alla volta.
Puoi usare il buon vecchio ed
per modificare un file in modo simile alla risposta che usa ex
. La grande differenza in questo caso è che ed
accetta i suoi comandi tramite input standard, non come argomenti della riga di comando come ex
può. Quando lo si utilizza in uno script, il modo normale per adattarlo è utilizzare printf
per 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