Eu tenho um arquivo cujo conteúdo é semelhante ao seguinte.
0
0
0.2
0
0
0
0
Eu preciso remover todas as linhas com um único zero.
Eu estava pensando em usar grep -v "0"
, mas isso remove também a linha que contém 0,2. Vi que poderia usar a -w
opção, mas isso também não parece funcionar.
Como posso remover todas as linhas que contêm apenas um único 0 e manter todas essas linhas começando com um 0?
-w
, que falha aqui.grep
para esta tarefa? E o que exatamente você quer dizer com um único zero ? Isso parece muito com um problema XY .Respostas:
De
man grep
:-w
falha porque o primeiro0
em0.02
é considerado uma "palavra", e, portanto, esta linha é correspondida. Isso ocorre porque é seguido por um caractere "não-palavra". Você pode ver isso se executar o comando original sem-v
, iegrep -w "0"
.fonte
-F
opção, uma vez que não estamos usando padrões de expressão regular, simplesmente cadeia correspondente-F
(surpreendentemente para mim) parece levar uma quantidade de tempo semelhante ou até um pouco mais lenta (~ 5 a 10%). Portanto, não tenho certeza de qual seria a vantagem.grep
presumivelmente tem um caso especial para expressões regulares sem metacaracteres, porque esse é um caso de uso comum. É surpreendente quefgrep
isso seja mais lento, mas não é surpreendente que a sobrecarga de perceber esse caso especial ao compilar um padrão curto seja insignificante em relação ao tempo para digitalizar um arquivo grande. (Se ele requer um caso especial em tudo para ir tão rápido, vs. um padrão com uma classe de caracteres oux.*y
.)grep
reconhece algum caractere que não seja\n
nova linha como um separador de linhas. Caso contrário, o implícito^
e$
ainda pode se transformar em uma pesquisa de cadeia fixa comostrstr(big_buf, "\n0\n")
. (Ou0\n
no início de um buffer.) Mas não estamos apenas procurando a primeira correspondência potencialmente distante em um grande buffer, queremos filtrar com eficiência. Mas de qualquer maneira, em teoria, sim, é apenas um memcmp de 2 bytes no início de cada linha, e você espera que tanto o fgrep quanto o grep vejam isso.Com grep:
^
significa início da linha,$
significa final da linha.fonte
[a-Z0-9]
Embora
grep
possa ser usado para isso (como outras respostas mostram claramente), vamos dar um passo atrás e pensar no que você realmente deseja:Regex interpreta os dados da sequência de caracteres. Eles não sabem sobre números, apenas sobre dígitos individuais (e combinações regulares dos mesmos). Embora no seu caso em particular haja uma simples invasão em torno dessa limitação, é uma incompatibilidade de requisitos.
A menos que haja uma boa razão para usar
grep
aqui (por exemplo, porque você a mediu, e é muito mais eficiente e a eficiência é crucial no seu caso), recomendo usar uma ferramenta diferente.awk
, por exemplo, pode filtrar com base em comparações numéricas, por exemplo:Mas também, para obter todas as linhas que contêm números maiores que zero:
Eu amo regex, é uma ótima ferramenta. Mas não é a única ferramenta. Como diz o ditado, se tudo o que você tem é
grep
, tudo parece uma linguagem comum.fonte
printf '0\n1\n-1\na\nb\n0\n0 also\n0.0\n-0.0\n0*0\n' | awk '($1 == 0)'
irá corresponder:0
,0.0
e-0.0
... e também0 also
! Não é apenas "0". (às vezes é necessário, às vezes não). Se o usuário quiser apenas "0":awk '/^0$/'
(ougrep '^0$'
). Você também deve editar: o usuário precisa adicionar!
para negar o teste, para ocultar0
(e outros zeros) e exibir o restante. ou seja:awk '!( $0 == 0)'
$1 == "0"
>
vez de!=
(ou equivalente! (… == …)
) , para destacar que esta é uma comparação numérica arbitrária, não apenas igualdade. Quanto ao seu outro comentário, isso é inteiramente verdade, mas estamos basicamente de volta ao território de comparação de strings e à solução existente usandogrep
works (embora, éawk
claro, também funcione).$0=="0"
grep
's-w
é um pouco complicado de uma maneira que divide a string original em constituintes de palavras e de não palavras (qualquer coisa, exceto letras, dígitos ou sublinhado). Uma vez que já encontrou aa constituinte palavra válida0
em0.02
que tinha afirmado a lógica negação para remover a linha.Usando
sed
é um pouco mais fácil, neste contexto, basta remover todo as palavras que jogofonte
Quando as linhas que você deseja excluir contêm apenas um
0
seguido pela próxima linha, você pode selecioná-las emitindo o seguinte comando:Isso imprimirá apenas as ocorrências
0
que estão no final de uma linha e no início de uma linha ao mesmo tempo. A-v
opção inverte nossa seleção.fonte
-v
, então ela não funciona.-v
opção, obrigado!grep -v "\b0\b"
grep -v "^0$"
-w funciona, mas no seu caso 0,2 são duas palavras porque o caractere de ponto é um separador de palavras.
fonte
grep -v "\b0\b"
realmente não funciona aqui. Qual versão do grep você usa?grep (BSD grep) 2.5.1-FreeBSD
no MacOS egrep (GNU grep) 2.16
no ubuntu\<
e\>
como limites da palavra, mas que terá o mesmo efeito que-w
Outra resposta por uma questão de variedade, supondo que você tenha um PCRE ativado
grep
isso executa um lookahead negativo para corresponder às linhas que começam com
0
e não são seguidas por um ponto. Em seguida,-v
descarta linhas não correspondentes. Você pode ver em ação aquifonte
0123
, o que não é o que o OP querSupondo que qualquer linha que não seja apenas um 0 tenha um período
grep '\.' file
fonte