Como fazer "se não for verdadeira condição"?

317

Gostaria de echoexecutar o comando quando isso cat /etc/passwd | grep "sysa"não for verdadeiro.

O que estou fazendo de errado?

if ! [ $(cat /etc/passwd | grep "sysa") ]; then
        echo "ERROR - The user sysa could not be looked up"
        exit 2
fi
Sandra Schlichting
fonte
7
O !não deve estar dentro dos colchetes? ie[ ! EXPR ]
acraig5075
7
@ acraig5075 é válido de qualquer maneira, mas não há necessidade de um comando de teste (que são os colchetes) nesta declaração.
Charles Duffy

Respostas:

455

experimentar

if ! grep -q sysa /etc/passwd ; then

grepretorna truese encontrar o alvo de pesquisa e falsese não encontrar.

Então NÃO false== true.

if a avaliação em shells é projetada para ser muito flexível e muitas vezes não requer cadeias de comandos (como você escreveu).

Além disso, olhando seu código como está, seu uso da $( ... )forma de substituição do cmd deve ser recomendado, mas pense no que está saindo do processo. Tente echo $(cat /etc/passwd | grep "sysa")ver o que eu quero dizer. Você pode levar isso adiante usando a -copção (count) para grep e depois executar o if ! [ $(grep -c "sysa" /etc/passwd) -eq 0 ] ; thenque funciona, mas é bastante antigo.

MAS, você pode usar os recursos mais recentes do shell (avaliação aritmética) como

if ! (( $(grep -c "sysa" /etc/passwd) == 0 )) ; then ...`

o que também oferece o benefício de usar os operadores de comparação baseados em c-lang ==,<,>,>=,<=,%e talvez alguns outros.

Nesse caso, por um comentário de Orwellophile, a avaliação aritmética pode ser reduzida ainda mais, como

if ! (( $(grep -c "sysa" /etc/passwd) )) ; then ....

OU

if (( ! $(grep -c "sysa" /etc/passwd) )) ; then ....

Finalmente, há um prêmio chamado Useless Use of Cat (UUOC). :-) Algumas pessoas vão pular para cima e para baixo e chorar gothca! Vou apenas dizer que greppode ter um nome de arquivo em sua linha de cmd, então por que invocar processos e construções de tubulação extras quando você não precisa? ;-)

Eu espero que isso ajude.

shellter
fonte
1
É tudo muito bobo, realmente, da minha resposta a uma pergunta muito mais difícil [ stackoverflow.com/a/30400327/912236] grep "^$user:" /etc/passwd seria a maneira mais correta de pesquisar / etc / passwd incidentalmente - grep -vonde -v inverte a pesquisa, se você quiser para evitar a bagunça de ||
Orwellophile
1
sim, resolvemos um problema com mais eficiência e depois respondemos a perguntas específicas. Eu tentei responder a pergunta específica. Obrigado por suas idéias. Boa sorte a todos.
shellter 01/06/2015
1
não escolhendo suas respostas, gostei bastante delas. Eu acabaria de lançar uma verificação devidamente delimitada do nome de usuário, caso contrário, se o OP realmente pesquisar "sys" ou algo assim, ele terá uma grande surpresa. mais um para a estrada? (( $( cat file | grep regex | wc -l ) ? 0 : 1 ))
Orwellophile
1
Ótimo! Por alguma razão, o reqular "! Grep -qs ..." não funcionou com / proc / mounts e tentou descobrir se um disco USB que estava caindo regularmente foi montado no kernel do Raspbian 4.9. Este fez o trabalho perfeitamente!
DocWeird)
33

Eu acho que pode ser simplificado em:

grep sysa /etc/passwd || {
    echo "ERROR - The user sysa could not be looked up"
    exit 2
}

ou em uma única linha de comando

$ grep sysa /etc/passwd || { echo "ERROR - The user sysa could not be looked up"; exit 2; }

Rony
fonte
4
Bom, mas eu prefiro a resposta do Sr. shellter porque é "auto-documentada", é mais "legível" da intenção do programador.
precisa saber é o seguinte
1
Eu gosto desta versão. Que tal adicionar 1>&2no final da sua echoimpressão stderr?
Jul15
2
@ 0zkrPM Mas a versão do shellter não funciona no shell Bourne. Você receberá!: not found
ceving 14/03
1
Evite o redirecionamento de saída ao usar 'grepassim. -qsuprime a saída.
tbc0
8

O que estou fazendo de errado?

$(...)mantém o valor , não o status de saída, é por isso que esta abordagem está errada. No entanto, nesse caso específico, ele realmente funciona porque sysaserá impresso, o que torna a declaração de teste realidade. No entanto, if ! [ $(true) ]; then echo false; fisempre seria impresso falseporque o truecomando não grava nada em stdout (mesmo que o código de saída seja 0). É por isso que ele precisa ser reformulado if ! grep ...; then.

Uma alternativa seria cat /etc/passwd | grep "sysa" || echo error. Edit: Como Alex apontou, gato é inútil aqui : grep "sysa" /etc/passwd || echo error.

Achei as outras respostas bastante confusas, espero que isso ajude alguém.

phil294
fonte
1

Nos sistemas Unix que o suportam (não parece o macOS):

if getent passwd "$username" >/dev/null; then
    printf 'User %s exists\n' "$username"
else
    printf 'User %s does not exist\n' "$username"
fi 

Isso tem a vantagem de consultar qualquer serviço de diretório que possa estar em uso (YP / NIS ou LDAP etc.) e o arquivo de banco de dados de senha local.


O problema grep -q "$username" /etc/passwdé que ele fornecerá um falso positivo quando esse usuário não existir, mas algo mais corresponderá ao padrão. Isso pode acontecer se houver uma correspondência parcial ou exata em outro lugar do arquivo.

Por exemplo, no meu passwdarquivo, há uma linha dizendo

build:*:21:21:base and xenocara build:/var/empty:/bin/ksh

Isso provocaria uma partida válida em coisas como carae enocetc., mesmo que não existem tais usuários em meu sistema.

Para que uma grepsolução esteja correta, você precisará analisar corretamente o /etc/passwdarquivo:

if cut -d ':' -f 1 /etc/passwd | grep -qxF "$username"; then
    # found
else
    # not found
fi

... ou qualquer outro teste semelhante ao primeiro dos :campos -delimited.

Kusalananda
fonte
@SDsolar Seu código provavelmente não será executado bashnesse caso.
precisa saber é o seguinte
1

Aqui está uma resposta a título de exemplo:

Para garantir que os registradores de dados estejam online, um cronscript é executado a cada 15 minutos, com a seguinte aparência:

#!/bin/bash
#
if ! ping -c 1 SOLAR &>/dev/null
then
  echo "SUBJECT:  SOLAR is not responding to ping" | ssmtp abc@def.com
  echo "SOLAR is not responding to ping" | ssmtp 4151112222@txt.att.com
else
  echo "SOLAR is up"
fi
#
if ! ping -c 1 OUTSIDE &>/dev/null
then
  echo "SUBJECT:  OUTSIDE is not responding to ping" | ssmtp abc@def.com
  echo "OUTSIDE is not responding to ping" | ssmtp 4151112222@txt.att.com
else
  echo "OUTSIDE is up"
fi
#

... e assim por diante para cada registrador de dados que você pode ver na montagem em http://www.SDsolarBlog.com/montage


FYI, o uso de &>/dev/nullredireciona toda a saída do comando, incluindo erros, para/dev/null

(O condicional requer apenas exit statuso pingcomando)

Além disso, para sua informação, observe que, como os crontrabalhos são executados, rootnão há necessidade de uso sudo pingem um cronscript.

SDsolar
fonte