Sair de um pipeline se um comando anterior falhar

Sair de um pipeline se um comando anterior falhar

Estou tentando verificar o número de trabalhos PBS em execução e na fila analisando a saída de qstat -tn1um bashscript. Até agora, isso funcionou:

count ()
{
    qstat -tn1 | awk '
        BEGIN { R = 0; Q = 0; }
        $10 == "R" { R++ }
        $10 == "Q" { Q++ }
        END { print R, Q }'
}

if read -r R Q < <(count)
    ...

No entanto, vejo que qstatocasionalmente falha por razões desconhecidas. Nesse caso, ele não imprime nada stdoute alguma mensagem de erro stderre sai com um status diferente de zero (bastante padrão). No entanto, awknão sabe que qstatfalhou e imprime com satisfação 0 0a entrada vazia que recebeu. Depois readatribui 0 para ambos Re Qsem saber que qstatrealmente falhou.

  1. Preciso inicializar Re Qcom 0 no BEGINbloco do awkscript, pois pode não haver processos em execução ou processos na fila, e preciso imprimir 0, não apenas uma string vazia, para o número desses processos.
  2. Eu poderia fazer isso set -o pipefail, o que permitiria countsair com um status diferente de zero, mas readnão consigo ver o status de saída e, de qualquer maneira, awké executado e imprime 0 0a entrada vazia.
  3. Eu poderia tentar um pipe nomeado e subprocessos, mas ter que gerenciá-los parece um exagero e muito complicado.

Existe alguma boa maneira de permitir que o chamador countdetecte sua falha?

Responder1

Acho que ler countuma substituição de processo impede que você obtenha seu status de retorno. Então não faça isso. Em vez disso, armazene o resultado em uma variável ou use um canal.

count=$(count)
if [ $? -eq 0 ]; then
  read -r R Q <<<"$count"

ou

set -o pipefail
if count | { read -r R Q; … }

Outra possibilidade é utilizar a PIPESTATUSvariável para verificar o status de retorno do primeiro comando.

count=$(qstat -tn1 | awk …)
if ((${PIPESTATUS[0]} == 0)); then
  read P Q

Alternativamente, faça com que o awk imprima algo distinto (por exemplo, nada) quando sua entrada estiver vazia.

awk '
    BEGIN { R = 0; Q = 0; }
    $10 == "R" { R++ }
    $10 == "Q" { Q++ }
    END { if (NR) print R, Q }'

Você pode testar se a entrada de um comando está vazia com ifnefrommaisutilsouOutros métodos. Mas como você está acessando o awk, é melhor fazer isso dentro do script awk que você já possui.

Se você precisar obter o status de retorno do qstatcomando, poderá alimentá-lo no awk como uma linha de entrada extra. Para facilitar a análise, faça com que a última linha tenha um formato exclusivo.

{
  qstat -tn1
  echo exit_code = $?
} | awk '
    /^exit_code = / { status = $3 }
    END { if (status == 0) print Q, R }
'

Responder2

Esse:

count ()
{
    { qstat -tn1 || echo "EPIC FAIL" } | awk '
        BEGIN { R = 0; Q = 0; }
        $10 == "R" { R++ }
        $10 == "Q" { Q++ }
        END { print R, Q }'
}

if read -r R Q < <(count)
    ...

Se qstatfor bem-sucedido, sua saída será enviada para awk. Se qstatretornar um status diferente de zero, o texto "EPIC FAIL" será enviado para awk.

Este é apenas um exemplo. Substitua o echo por algo apropriado que você possa manipular dentro awkou com if read.

informação relacionada