shell - trabalhando - utilizando o sed no linux
Excluir linhas em um arquivo de texto que contenha uma string específica (10)
Como eu usaria o sed para excluir todas as linhas em um arquivo de texto que contenha uma string específica?
A maneira mais fácil de fazer isso, com o GNU sed
:
sed --in-place '/some string here/d' yourfile
Apenas no caso de alguém querer fazer isso por combinações exatas de strings, você pode usar o flag -w
no grep -w para todo. Ou seja, por exemplo, se você deseja excluir as linhas que possuem o número 11, mas mantenha as linhas com o número 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
Ele também funciona com o sinalizador -f
se você quiser excluir vários padrões exatos de uma só vez. Se "lista negra" é um arquivo com vários padrões em cada linha que você deseja excluir do "arquivo":
grep -w -v -f blacklist file
Eu fiz um pequeno benchmark com um arquivo que contém aproximadamente 345 000 linhas. O caminho com o grep
parece ser cerca de 15 vezes mais rápido que o método sed
neste caso.
Eu tentei tanto com e sem a configuração LC_ALL = C, não parece alterar os horários de forma significativa. A cadeia de pesquisa (CDGA_00004.pdbqt.gz.tar) está em algum lugar no meio do arquivo.
Aqui estão os comandos e os horários:
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
Existem muitas outras maneiras de excluir linhas com strings específicas além do sed
:
AWK
awk '!/pattern/' file > temp && mv temp file
Rubi (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 posterior)
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, claro, sed
(imprimir o inverso é mais rápido que a exclusão real):
sed -n '/pattern/!p' file
Para remover a linha e imprimir a saída como padrão:
sed '/pattern to match/d' ./infile
Para modificar diretamente o arquivo:
sed -i '/pattern to match/d' ./infile
Para modificar diretamente o arquivo (e criar um backup):
sed -i.bak '/pattern to match/d' ./infile
Para usuários do Mac OS X e FreeBSD:
sed -i '' '/pattern/d' ./infile
Você pode usar sed para substituir linhas no lugar em um arquivo. No entanto, parece ser muito mais lento do que usar grep para o inverso em um segundo arquivo e, em seguida, mover o segundo arquivo sobre o original.
por exemplo
sed -i '/pattern/d' filename
ou
grep -v "pattern" filename > filename2; mv filename2 filename
O primeiro comando demora 3 vezes mais tempo na minha máquina.
Você também pode usar isto:
grep -v 'pattern' filename
Aqui -v
imprimirá apenas outro que não o seu padrão (isso significa que a correspondência invertida).
cat filename | grep -v "pattern" > filename.1
mv filename.1 filename
perl -i -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3
O primeiro comando edita o (s) arquivo (s) no local (-i).
O segundo comando faz a mesma coisa, mas mantém uma cópia ou backup do (s) arquivo (s) original (is) adicionando .bk aos nomes dos arquivos (o .bk pode ser alterado para qualquer coisa).