Eu tenho um comando com o qual estou executando curl
. O comando curl sempre resolve com sucesso, mesmo quando a resposta do servidor inclui a string ERROR em algum lugar.
Posso de alguma forma detectar essa resposta com algum tipo de script ou função de shell (preferencialmente zsh), enquanto também encaminha a saída para o terminal e torna o comando geral falso?
Não sei exatamente o que você deseja alcançar, mas acho que você precisa de um
tee
ou de um redirecionamento da saída de errocurl -s whatever 2>&1|tee output.txt|grep ERROR
então ambos têm o grep do erro e o conteúdo do comando curl no arquivo output.txt.
Por favor, veja a primeira parte desta outra resposta minha e os links nela. Você deseja detectar uma string. Fazer
curl
falhar de acordo com o código de erro HTML parece mais elegante. Se for possível obter o resultado desejado desta forma, então é o Caminho Certo.Caso contrário, use a seguinte função shell de uso geral:
Uso:
O objetivo principal da função é retornar o status de saída diferente de zero se a saída de
command [arg...]
contiver uma linha correspondente aopattern
. A saída é impressa no stdout da função, independentemente de haver uma correspondência ou não.Exemplo:
Observações e explicações:
O
pattern
é fornecido como está paragrep
, portanto, é um regex. Um vazio ou indefinidopattern
corresponderá a qualquer linha, se apenas houver uma linha.A função deve funcionar em bash, zsh e muitos outros shells. AFAIK a sintaxe do shell que usei é portátil. Coisas não portáteis são independentes do shell, exceto
set -o pipefail
o que pertence ao shell e não é portátil. Quero dizer ainda não. É amplamente suportado e será adicionado ao padrão POSIX .Graças a
pipefail
, se o padrão não for encontrado etee
não falhar (normalmente não deve falhar), a função retornará o status de saída do comando especificado (por exemplocurl
, ).Se o padrão for encontrado, a função retornará
125
. Eu escolhi125
porque:não é reservado ,
man 1 curl
no meu sistema operacional especifica códigos de saída até96
já e mais podem aparecer no futuro.Você pode ajustar esse número às suas necessidades por
FAILON_STATUS
meio da variável de ambiente. Por exemploFAILON_STATUS=120 failon …
. A notaFAILON_STATUS=0
é tecnicamente válida, mas bastante inútil.tee -p
não é portátil. Sem-p
tee
sairá se ficarSIGPIPE
depoisgrep
de sair mais cedo.grep -q
sai assim que encontra o padrão. Graças a-p
tee
irá retransmitir toda a sua entrada para/proc/self/fd/3
(que é, em última análise, o stdout da função), mesmo quegrep
saia mais cedo.Se você
tee
não oferece suporte-p
, a solução mais simples é usargrep -- "$pattern" >/dev/null
. Agoragrep
processará silenciosamente todos os dados, não sairá mais cedo. A desvantagem é que ele fará linhas de correspondência de trabalho desnecessárias depois que o padrão for encontrado pela primeira vez./proc/self/fd/…
não é portátil; espero que seu sistema operacional suporte isso. Mesmo que isso não aconteça, sempre há um métodocurl … | tee /temporary/file
seguido por! grep -q ERROR /temporary/file
para obter o status de saída falso emERROR
. Este método é bastante direto e KISS , mas:em um de seus comentários você disse que não quer salvar a saída em um arquivo;
em geral, não é fácil criar um arquivo
/temporary/file
;mktemp
é a ferramenta certa, mas não é especificada pelo POSIX.Em zsh você pode fazer
"$@" >&3 | { grep -q …
(em vez de"$@" | tee … | { grep -q …
) e assim se livrar detee -p /proc/self/fd/3
qualquer problema potencial dele.--
é explicado aqui: O que significa--
(traço duplo)?Se
command
não for especificado, a função usarácat
. Isso permite que você usefailon
como um "filtro":Observe que é fácil perder o status de saída
curl
dessa maneira. Por outro lado, é possível fazer isso:e examine
PIPESTATUS
(no bash) oupipestatus
(no zsh) para detectarERROR
eWARNING
na saída independentemente.Alguns programas mudam seu comportamento, dependendo de stdout ser um terminal, um pipe ou um arquivo regular (veja como enganar um comando para pensar que sua saída está indo para um terminal ). Nossa função usa internamente um pipe, então em alguns casos a saída de
failon foo program
será diferente da saída da mesmaprogram
invocada diretamente.