Grep remove a linha com 0, mas não com 0,2?


12

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 -wopçã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?


2
Possível duplicado de Jogo cadeia exata usando grep
Julien Lopez

1
@JulienLopez Não é um engano dessa pergunta. Essa pergunta é sobre como corresponder uma palavra e respondida com -w, que falha aqui.
Sparhawk

Por que você é forçado a usar greppara esta tarefa? E o que exatamente você quer dizer com um único zero ? Isso parece muito com um problema XY .
Roland Illig 15/02/19

1
@RolandIllig, era 1 hora antes de dormir e eu queria começar a processar uma série de 500.000 strings para verificar se eram chaves privadas de bitcoin e, se sim, para obter equilíbrio. Na próxima vez que tive tempo de analisar, havia processado milhares de strings e só queria analisar valores diferentes de zero.
Philip Kirkbride

Respostas:


35
grep -vx 0

De man grep:

-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 $.

-wfalha porque o primeiro 0em 0.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, ie grep -w "0".


Você também pode usar a -Fopção, uma vez que não estamos usando padrões de expressão regular, simplesmente cadeia correspondente
glenn jackman

@glennjackman Talvez eu tenha lido isso antes, mas não consigo encontrá-lo agora. Correr com -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.
Sparhawk

2
É possível que o mecanismo RegEx seja usado com tanta frequência e tão amplamente que eles tenham implementado uma versão muito eficiente, mas que uma "pesquisa simples" provavelmente não tenha sido atualizada por 30 anos.
194 Nelson Nelson

@ Sparhawk: greppresumivelmente tem um caso especial para expressões regulares sem metacaracteres, porque esse é um caso de uso comum. É surpreendente que fgrepisso 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 ou x.*y.)
Peter Cordes

Mas isso talvez seja uma simplificação excessiva, porque a entrada é na verdade muitas linhas curtas (não uma corda gigante). Eu esqueço se grepreconhece algum caractere que não seja \nnova linha como um separador de linhas. Caso contrário, o implícito ^e $ ainda pode se transformar em uma pesquisa de cadeia fixa como strstr(big_buf, "\n0\n"). (Ou 0\nno 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.
Peter Cordes

28

Com grep:

grep -v "^0$" file

^significa início da linha, $significa final da linha.


2
É isso que o usuário solicitou: evite qualquer linha que contenha apenas 1 "0".
Olivier Dulac

1
Eu não colocaria um cifrão literal entre aspas duplas assim.
user541686

@mehrdad não que grande problema com regex como é geralmente ou último caractere ou próximo não vai ser[a-Z0-9]
Sampo Sarrala - codidact.org

14

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:

  • Você tem um arquivo contendo números
  • Você deseja executar a filtragem com base no valor numérico .

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 grepaqui (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:

awk '$1 == 0' your_file

Mas também, para obter todas as linhas que contêm números maiores que zero:

awk '$1 > 0' your_file

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.


3
Concordo plenamente que o awk pode ser mais elegante aqui ... no entanto, também corresponderá talvez um pouco mais do que o que o usuário espera (todo valor numérico avaliado como 0). Ou seja, 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.0e -0.0... e também 0 also! Não é apenas "0". (às vezes é necessário, às vezes não). Se o usuário quiser apenas "0": awk '/^0$/' (ou grep '^0$'). Você também deve editar: o usuário precisa adicionar !para negar o teste, para ocultar 0(e outros zeros) e exibir o restante. ou seja:awk '!( $0 == 0)'
Olivier Dulac

1
@Olivier, ou verifique o valor da string:$1 == "0"
glenn jackman

1
@OlivierDulac Eu usei explicitamente, em >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 usando grepworks (embora, é awkclaro, também funcione).
Konrad Rudolph

@KonradRudolph fair points :)
Olivier Dulac

1
@glennjackman: bom truque, de fato. Mas então OP preferiria fazer teste$0=="0"
Olivier Dulac

5

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álida 0em 0.02que 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 jogo

sed '/^0$/d' file

3

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:

grep -v "^0$"

Isso imprimirá apenas as ocorrências 0que estão no final de uma linha e no início de uma linha ao mesmo tempo. A -vopção inverte nossa seleção.


1
Essa resposta é quase idêntica à de Arkadiusz Drabczyk, mas você esqueceu a -v, então ela não funciona.
Sparhawk

Você está certo. Eu estava digitando enquanto ele postava sua resposta, então não vi que ela já foi dada. Eu li mal essa parte com a -vopção, obrigado!
majesticLSD

0
  • \ b - borda da palavra

grep -v "\b0\b"

  • coincidir com o início da linha, seu padrão e o fim da linha

grep -v "^0$"

  • ou como @Sparhawk sugeriu -vx lineregexp

-w funciona, mas no seu caso 0,2 são duas palavras porque o caractere de ponto é um separador de palavras.


grep -v "\b0\b"realmente não funciona aqui. Qual versão do grep você usa?
Arkadiusz Drabczyk 14/02/19

trabalha com grep (BSD grep) 2.5.1-FreeBSDno MacOS e grep (GNU grep) 2.16no ubuntu
Jakub Jindra

1
GNU regex uso \<e \>como limites da palavra, mas que terá o mesmo efeito que-w
Glenn Jackman

0

Outra resposta por uma questão de variedade, supondo que você tenha um PCRE ativado grep

grep -Pv "^0(?!\.)"

isso executa um lookahead negativo para corresponder às linhas que começam com 0e não são seguidas por um ponto. Em seguida, -vdescarta linhas não correspondentes. Você pode ver em ação aqui


1
Isso também irá remover linhas tais como 0123, o que não é o que o OP quer
Iruvar

0

Supondo que qualquer linha que não seja apenas um 0 tenha um período

grep '\.' file

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.