Impedir a saída do grep em caso de incompatibilidade

29

Este script não ecoa "depois":

#!/bin/bash -e

echo "before"

echo "anything" | grep e # it would if I searched for 'y' instead

echo "after"
exit

Também removeria a -eopção na linha shebang, mas desejo mantê-la para que meu script pare se houver um erro. Não considero grep encontrar nenhuma correspondência como um erro. Como posso impedir que ele saia tão abruptamente?

iago-lito
fonte
Esta é uma observação feita apenas para consideração. Talvez a lógica desse script deva ser pensada novamente. Se não é importante encontrar a sequência, por que procurá-la? A definição de grep é tal que se toma decisões com base na presença ou ausência de uma string. Se você não se importa, então não é importante. Além disso, parece -epressupor que você se importe: tanto que qualquer problema é catastrófico.
Andrew Falanga
2
@AndrewFalanga Eu me importo de qualquer maneira, pois na verdade estou analisando o conteúdo var=$(complex command | grep complex_pattern)que pode ser nulo (nesse caso, meu programa não deve terminar). Este é apenas um script resumido que faz com que o problema ocorra. Nenhum buraco negro metafísico na lógica aqui, certo? ;)
iago-lito
Saber agora que você pretendia capturar a saída esclarece algumas coisas. Como apresentado, foi confuso para mim.
Andrew Falanga

Respostas:

33
echo "anything" | grep e || true

Explicação:

$ echo "anything" | grep e
### error
$ echo $?
1
$ echo "anything" | grep e || true
### no error
$ echo $?
0
### DopeGhoti's "no-op" version
### (Potentially avoids spawning a process, if `true` is not a builtin):
$ echo "anything" | grep e || :
### no error
$ echo $?
0

O "||" significa "ou". Se a primeira parte do comando "falhar" (significando "grep e" retorna um código de saída diferente de zero), a parte após o "||" é executado, obtém êxito e retorna zero como o código de saída ( truesempre retorna zero).

John N
fonte
3
Uma versão ligeiramente mais curta do mesmo que não aparece /bin/trueé: command || :(no seu caso set -e; grep 'needle' haystack || :).
DopeGhoti
1
@DopeGhoti, trueé um componente embutido em algumas conchas (pelo menos bash 4.3no RHEL) #
iruvar
3
Não é válido porque, se o primeiro comando falhar, ocultará o erro. Uma solução correta deve retornar zero se o primeiro comando no pipe falhar.
sorin
11

Uma maneira robusta de enviar mensagens de forma segura e opcional grep :

echo something | grep e || [[ $? == 1 ]] ## print 'something', $? is 0
echo something | grep x || [[ $? == 1 ]] ## no output, $? is 0
echo something | grep --wrong-arg e || [[ $? == 1 ]] ## stderr output, $? is 1

De acordo com o manual do posix , o código de saída 1 significa que nenhuma linha foi selecionada e> 1 significa um erro.

James ZM Gao
fonte
1
Essa deve ser a resposta aceita, pois apenas suprime o código de saída de aviso (1) se o grep não encontrar nada, mas transmite erros verdadeiros (códigos de saída> 1). As outras soluções aqui sempre suprimem erros verdadeiros, o que geralmente é ruim.
HaroldFinch
7

Outra opção é adicionar outro comando ao pipeline - um que não falha:

echo "anything" | grep e | cat

Como catagora é o último comando no pipeline, é o status de saída cat, e não de grep, que será usado para determinar se o pipeline falhou ou não.

roelvanmeer
fonte
4

Outra opção:

...
set +e
echo "anything" | grep e
set -e
...
Jeff Schaller
fonte
3

Solução

#!/bin/bash -e

echo "before"

echo "anything" | grep e || : # it would if I searched for 'y' instead

echo "after"
exit

Explicação

set -e ou set -o errexit

Saia imediatamente se um pipeline (que pode consistir em um único comando simples ), uma lista ou um comando composto (veja SHELL GRAMMARacima), sair com um status diferente de zero. O shell não sai se o comando que falhar faz parte da lista de comandos imediatamente após uma palavra while- untilchave ou , parte do teste após as palavras reservadas ifou elifparte de qualquer comando executado em uma lista &&ou, ||exceto o comando após o final &&ou ||qualquer comando em um pipeline, mas o último, ou se o valor de retorno do comando estiver sendo invertido com!. Se um comando composto que não seja um subshell retorna um status diferente de zero porque um comando falhou enquanto -eestava sendo ignorado, o shell não sai. Uma interceptação ERR, se definida, é executada antes da saída do shell. Esta opção se aplica ao ambiente do shell e a cada ambiente do sub-shell separadamente (veja COMMAND EXECUTION ENVIRONMENTacima), e pode causar a saída de sub-shell antes de executar todos os comandos no sub-shell .

Além disso, :é o comando sem efeito no Bash.

Cyker
fonte