O grep pode retornar true / false ou existem métodos alternativos

130

Como parte desse script, preciso verificar se o primeiro argumento fornecido corresponde à primeira palavra do arquivo. Se houver, saia com uma mensagem de erro; caso contrário, anexe os argumentos ao arquivo. Eu entendo como escrever a ifdeclaração, mas não como usar grepem um script. Eu entendo que grepserá algo parecido com isto

grep ^$1 schemas.txt

Eu sinto que isso deve ser muito mais fácil do que estou fazendo.

Estou recebendo um erro "muitos argumentos" na ifdeclaração. Eu me livrei do espaço entre elas grep -qe recebi um erro que o operador binário esperava.

if [ grep -q ^$1 schemas.txt ]
then
        echo "Schema already exists. Please try again"
        exit 1
else
        echo "$@" >> schemas.txt
fi
Lauren
fonte
11
Perca o [... ]e vai funcionar. Embora você provavelmente queira citar seu padrão:if grep -q "^$1" schemas.txt; then …
derobert 18/09/12
uma solução de linha usando o recurso de Bash "Command Grupo": stackoverflow.com/questions/6550484/...
Trevor Boyd Smith

Respostas:

186

grepretorna um código de saída diferente se encontrou algo (zero) vs. se não encontrou nada (diferente de zero). Em uma ifinstrução, um código de saída zero é mapeado para "true" e um código de saída diferente de zero é mapeado para false. Além disso, o grep tem um -qargumento para não gerar o texto correspondente (mas retornar apenas o código de status de saída)

Então, você pode usar o grep assim:

if grep -q PATTERN file.txt; then
    echo found
else
    echo not found
fi

Como uma observação rápida, quando você faz algo como if [ -z "$var" ]…, acontece que [na verdade é um comando que você está executando, assim como o grep. No meu sistema, é /usr/bin/[. (Bem, tecnicamente, seu shell provavelmente o possui, mas isso é uma otimização. Ele se comporta como se fosse um comando). Funciona da mesma maneira, [retorna um código de saída zero para true, e um código de saída diferente de zero para false. ( testé a mesma coisa que [, exceto no fechamento ])

derobert
fonte
Por que a instrução if não precisa dos colchetes? Eu tenho que trabalhar sem, mas não entendo o porquê. Ainda posso aninhá-lo sem os colchetes?
Lauren
@Lauren você perdeu a nota rápida? [Não é parte da sintaxe se, é (conceitualmente) um comando que você está executando, assim como grep
derobert
2
@Lauren Você não usa grep dentro de [, você usa um ou outro, dependendo da condição que deseja verificar. (Você pode usar qualquer comando dentro de um if, btw, se apenas verificar o código de saída.) ... bem, acho que você provavelmente poderia ter uma razão para usar o grep inside [, mas isso seria um script bastante complicado e seu não é uma coisa normal a se fazer.
Derobert 18/09/12
3
Para sua informação, corra ls -l /usr/bin/\[e, man [para ver que [é um programa como outro qualquer, apenas parece um elemento sintático - isso deve tornar óbvio e fácil de entender. (por conveniência, [também é incorporado no bash, dash e outros - mas ainda é um comando). também tente type -all [no bash.
cas
11
@AlexanderCska se você quiser que o grep imprima as linhas correspondentes (por exemplo, para canalizá-las em algum lugar) e, em seguida, omita a -qopção que diz ao grep para ficar quieto (não imprima as linhas correspondentes).
derobert 22/07
48

Outra maneira simples é usar grep -c.

Isso gera (não retorna como código de saída), o número de linhas que correspondem ao padrão; portanto, 0 se não houver correspondência ou 1 ou mais se houver correspondência.

Portanto, se você quiser verificar se o padrão é correspondido 3 ou mais vezes, faça:

if [ "$(grep -c "^$1" schemas.txt)" -ge 3 ]; then
  ...
amigal
fonte
17
Mais precisamente, ele produzirá 1 se encontrado apenas uma vez. Para gerar 1 independentemente da quantidade de correspondências encontradas, use em grep -cim1vez disso.
manatwork
Este método também pode ser usado para distinguir entre erro grep e grep 'padrão encontrado 0 vezes'. (embora não com a declaração exata se usada, acho que uma variável é necessária)
Evan Benn
3

Eu sei que estou atrasado para isso, mas eu amo esta versão curta:

grep -q ^$1 schemas.txt && echo "Schema already exists. Please try again" || echo "$@" >> schemas.txt
Denis Pitzalis
fonte
0

Se queremos pegar a primeira palavra de um arquivo, precisamos adicionar -zwao grep

if grep -qzw "^$1" file
then 
   ... 
else 
   ... 
fi

Sem -zobter a primeira palavra de uma linha. Sem -wtermos palavras parciais.

JJoao
fonte
-2

Se você quiser usá-lo com colchetes, você pode executar o procedimento abaixo

if [ `grep -q PATTERN file.txt` ]; then
    echo found
else
    echo not found

Essa lógica funciona para todos os comandos. Basta colocar seus comandos dentro do backtick (o botão acima da guia ou na parte inferior do botão Esc ou à esquerda do botão 1)

k_vishwanath
fonte
11
Você precisaria citar o `grep -q PATTERN file.txt`, caso contrário, o operador split + glob será aplicado e isso causaria problemas para qualquer saída que contenha caracteres $IFSou caracteres curinga. De maneira mais geral, [ "`cmd`" ]retornaria true se cmdgerar pelo menos uma linha não vazia no stdout (com problemas em potencial se gerar NUL bytes). Isso significa que o shell precisará armazenar toda a saída na memória e aguardar o término. O uso if cmd | grep -q .pode ser preferível nesse sentido.
Stéphane Chazelas
Este comando não faria sentido algum. O objetivo do -qswitch é suprimir grep a saída. Você está dizendo: Verifique PATTERN no arquivo.txt, suprima qualquer saída e defina o status de retorno de acordo com a localização do PATTERN. Em seguida, ignore o status de retorno, pegue a saída do comando (que forçamos a ficar vazia), aplique a divisão de palavras e a expansão do arquivo global (resultando em nenhum argumento) e execute o comando [(aka test) com exatamente um argumento - a saber , ]--e então, como isso resultará em um erro, ecoe "não encontrado". @ StéphaneChazelas, eu perdi alguma coisa?
Curinga
11
@ Wildcard, você está certo, eu aparentemente esqueci o -q. Esse comentário teria feito sentido [ `grep PATTERN file.txt ` ], mas, como sugerido no comentário, [ "`grep -n PATTERN file.txt`" ]seria melhor se PATTERN corresponder apenas a linhas vazias. Embora aqui, é claro, if grep -q PATTERN file.txtvocê queira.
Stéphane Chazelas