Come utilizzerei sed per cancellare tutte le righe in un file di testo che contiene una stringa specifica?
Per rimuovere la linea e stampare l'output su standard:
sed '/pattern to match/d' ./infile
Per modificare direttamente il file:
sed -i '/pattern to match/d' ./infile
Per modificare direttamente il file (e creare un backup):
sed -i.bak '/pattern to match/d' ./infile
Per utenti Mac OS X e FreeBSD:
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
(stampare l'inverso è più veloce dell'effettiva cancellazione):
sed -n '/pattern/!p' file
Puoi usare sed per sostituire le linee in posizione in un file. Tuttavia, sembra essere molto più lento rispetto all'utilizzo di grep per l'inverso in un secondo file e quindi lo spostamento del 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 di più sulla mia macchina.
Il modo semplice per farlo, con GNU sed
:
sed --in-place '/some string here/d' yourfile
Puoi prendere in considerazione l'utilizzo di ex
(che è un editor basato su comandi Unix standard):
ex +g/match/d -cwq file
dove:
+
esegue il comando Ex dato (man ex
), come -c
che esegue wq
(scrivi e chiudi)g/match/d
- Ex comando per cancellare le righe con match
, vedi: Power of gL'esempio precedente è un metodo conforme a POSIX per la modifica diretta di un file secondo questo post a Unix.SE e specifiche POSIX per ex
.
La differenza con sed
è che:
sed
è un S tream ED itor, non un editor di file.BashFAQ
A meno che non ti piaccia codice inopportuno, sovraccarico I/O e altri effetti collaterali negativi. Quindi in pratica alcuni parametri (come in-place/-i
) sono estensioni FreeBSD non standard e potrebbero non essere disponibili su altri sistemi operativi.
Ero alle prese con questo su Mac. Inoltre, avevo bisogno di farlo usando la sostituzione variabile.
Quindi ho usato:
sed -i '' "/$pattern/d" $file
dove $file
è il file in cui è necessaria l'eliminazione e $pattern
è il modello da abbinare per la cancellazione.
Ho scelto ''
da questo commento .
La cosa da notare qui è l'uso di doppie virgolette in "/$pattern/d"
. La variabile non funzionerà quando usiamo le virgolette singole.
Per ottenere un risultato simile come grep
puoi farlo:
echo "$(grep -v "pattern" filename)" >filename
Ho fatto un piccolo benchmark con un file che contiene circa 345.000 linee. In questo caso, il modo con grep
sembra essere circa 15 volte più veloce rispetto al metodo sed
.
Ho provato entrambi con e senza l'impostazione LC_ALL = C, non sembra cambiare significativamente i tempi. La stringa di ricerca (CDGA_00004.pdbqt.gz.tar) è 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
stamperà solo altro che il tuo pattern (che significa invert match).
echo -e "/thing_to_delete\ndd\033:x\n" | vim file_to_edit.txt
Perl -i -nle'/regexp/||print' file1 file2 file3
Perl -i.bk -nle'/regexp/||print' file1 file2 file3
Il primo comando modifica il file (s) inplace (-i).
Il secondo comando fa la stessa cosa ma conserva una copia o un backup dei file originali aggiungendo .bk ai nomi dei file (.bk può essere cambiato in qualsiasi cosa).
cat filename | grep -v "pattern" > filename.1
mv filename.1 filename
Nel caso in cui qualcuno volesse farlo per le corrispondenze esatte delle stringhe, puoi usare il flag -w
in grep -w per intero. Cioè, per esempio se vuoi cancellare le linee che hanno il numero 11, ma mantieni le linee 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 il flag -f
se vuoi escludere più pattern esatti contemporaneamente. Se "lista nera" è un file con più motivi su ciascuna riga che si desidera eliminare da "file":
grep -w -v -f blacklist file