Como obter o PIPESTATUS e a saída no script bash

8

Estou tentando obter a data da última modificação de um arquivo com este comando

TM_LOCAL='ls -l --time-style=long-iso ~/.vimrc | awk '{ print $6" "$7 }''

TM_LOCAL tem valor como "2012-05-16 23:18" após a execução desta linha

Eu também gostaria de verificar o PIPESTATUS para ver se houve um erro. Por exemplo, se o arquivo não existir, ls retornará 2. Mas $? terá valor 0, pois possui o valor de retorno de awk .

Se eu executar este comando sozinho, posso verificar o valor de retorno de ls observando ${PIPESTATUS[0]}

ls -l --time-style=long-iso ~/.vimrc | awk '{ print $6" "$7 }'

Mas $PIPESTATUS não funciona como eu esperava se eu atribuísse a saída a uma variável como no primeiro exemplo. Nesse caso, $PIPESTATUS array tem apenas 1 elemento, que é igual a $?

Então, a pergunta é: como posso obter os dois $PIPESTATUS e atribuir a saída a uma variável ao mesmo tempo?

    
por Mustafa Serdar Şanlı 17.05.2012 / 21:25

6 respostas

7

Você pode fazer isso:

TM_LOCAL=$(ls -l --time-style=long-iso ~/.vimrc | \
             awk '{ print $6" "$7 }' ; exit ${PIPESTATUS[0]} )

Em seguida, $? será o código de retorno de ls . Isso não funciona se você precisar do código de retorno de mais de uma das partes do pipe (mas você pode dividir o pipeline se a saída não for muito grande, como é aqui).

Aqui está uma maneira bastante cara de obter o array PIPESTATUS completo e a saída. Não é muito elegante, mas não encontrou mais nada:

result=$(echo -e "a\nb\nc" | \
          ( cat ; exit 1 ) | \
          ( cat ; exit 42 ) ; echo ${PIPESTATUS[@]})
output=$(head -n -1 <<< "$result")
status=($(tail -n 1 <<< "$result"))
echo "Output:"
echo "$output"
echo "Results:"
echo "${status[@]}"

O que dá:

Output:
a
b
c
Results:
0 1 42
    
por 17.05.2012 / 21:51
3

Use set -o pipefail em bash para obter o código de saída diferente de zero mais à direita em uma sequência de comandos canalizada como $? . De man bash :

If set, the return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands in the pipeline exit successfully. This option is disabled by default.

Então você pode simplesmente acessar $? . Use set +o pipefail para desativar novamente.

    
por 01.07.2013 / 10:05
3

Eu assumo que o problema aqui é que o PIPESTATUS desaparece em sua totalidade assim que você executa um comando. Você pode obter o array PIPESTATUS completo na versão 2 do bash ou acima desta maneira:

declare -a status
status=(${PIPESTATUS[@]})

Em seguida, acesse ${status[0]} , ${status[1]} , etc.

    
por 12.08.2014 / 17:11
2

O principal problema com "o que você espera" é que um comando em backquotes é executado em um subshell; $PIPESTATUS existe lá e o status retornado fromm segue as mesmas regras como se você tivesse executado um único executável (ou shell script). O status do comando backquote é o status mais à direita ( awk ).

Para implementar o que @ Daniel Beck disse, defina a opção pipefail no subshell assim:

TM_LOCAL='set -o pipefail; ls -l --time-style=long-iso ~/.vimrc | awk '{ print $6" "$7 }'' agora o status armazenado em $? depois será o status de ls (se diferente de zero).

No entanto, acho que um teste if [ -f ~/.vimrc ]; ... explícito seria mais legível.

Você não pode obter saída em uma variável e PIPESTATUS retornou sem um arquivo temporário para o primeiro, ou empacotando o último em uma cadeia de caracteres.

    
por 01.03.2018 / 21:08
0

Uma opção é verificar a existência do seu arquivo antes obtendo seu tempo de modificação com uma chamada para stat . Desde a stat retorna um pouco mais do que você deseja no timestamp, você pode cortá-lo usando a expansão de parâmetro

[[ -f ~/.vimrc ]] && TM_LOCAL=$(stat -c '&y' ~/.vimrc 2>/dev/null)
TM_LOCAL=${TM_LOCAL%:*}  # Safe to do, even if stat fails
    
por 17.05.2012 / 22:37
0

Eu queria enviar o email fron cron somente se o status de saída não fosse zero

O truque é que para obter o stdin para o final do pipeline você precisa colocá-lo em um subshell - mas isso parece esconder o valor PIPESTATUS ...

teste cron produz uma saída e sai com 1 ou 0 ..

./testcron | (test ${PIPESTATUS[0]} -ne 0 || mail -s "testcron output" paul)

UPDATE: o PIPESTATUS não é visível até que o comando do pipeline seja processado

    
por 06.06.2012 / 12:12

Tags