Sair do status de um processo assíncrono

1

Embora o comando a seguir retorne um status de saída que depende da existência do arquivo remoto:

ssh $userAtServer "ls $targetDir/$targetFile" > $sshOutputFile
lsReturnValue=$?

que eu posso testar para fazer algumas coisas, às vezes trava (1 de 10 ou 20) e bloqueia a execução de código adicional.

Portanto, preciso executar um comando ssh como este e recuperar o valor de saída da função ls:

(ssh $userAtServer "ls $targetDir/$targetFile" > $sshOutputFile ; lsReturnValue=$?) &
timeOutProcess $!

No entanto, lsReturnValue sempre retorna uma string vazia.

timeOutProcess é uma função que mata meu comando se durar muito tempo:

timeOutProcess() {
    processId=$1

    #from http://www.bashcookbook.com/bashinfo/source/bash-4.0/examples/scripts/timeout3
    timeout=45
    interval=2
    delay=5
    (
        ((t = timeout))

        while ((t > 0)); do
            sleep $interval
            kill -0 $processId || return 0
            ((t -= interval))
        done
        # Be nice, post SIGTERM first.
        # The 'exit 0' below will be executed if any preceeding command fails.
        kill -s SIGTERM $processId && kill -0 $processId || exit 0
        sleep $delay
        kill -s SIGKILL $processId
    ) 2> /dev/null  
}

Eu me pergunto como eu poderia conseguir o $? valor do comando ssh?

    
por lauhub 26.03.2013 / 01:58

2 respostas

1

Você tem duas maneiras de obter o status de retorno do processo ssh usando os recursos padrão do shell: execute-o de forma síncrona ou chame o wait builtin. Quando você corre

(ssh $userAtServer "ls $targetDir/$targetFile" > $sshOutputFile ; lsReturnValue=$?) &

isso somente define lsReturnValue na subshell, e você não pode obter nenhuma informação diferente do status de retorno para o shell pai. Então você teria que executar exit $lsReturnValue da subshell e obter o status de retorno da subshell do shell pai; e então todo o processo de background poderia ser simplificado para ssh $userAtServer "ls $targetDir/$targetFile" > $sshOutputFile & de qualquer maneira.

Esse trecho de shell que você encontrou para permitir que um comando atinja o tempo limite não é muito bom porque não retém o status de retorno. No Linux, use o utilitário timeout .

Sem o utilitário timeout , fica um pouco complicado. Você precisa executar dois subprocessos: aquele em que está interessado e um que executa sleep para a parte de tempo limite. Se um dos processos retornar, ele deverá matar o outro e permitir que o shell prossiga. Infelizmente, o wait builtin aguarda até que todos os subprocessos tenham morrido quando você o chama sem argumento. Uma maneira de sincronizar os dois processos é fazer com que eles gravem em um pipe e os matem quando aparecerem alguns dados no pipe.

lsReturnValue=$(
  {
    { ssh $userAtServer "ls $targetDir/$targetFile" > $sshOutputFile
      echo $?; } &
    { sleep 5; echo timeout; } &
  } | head -n 1)
if [ "$lsReturnValue" = "timeout" ]; then …

Se você estiver enviando comandos para vários servidores, considere seriamente usar um estrutura multi-servidor ssh como mussh, clusterssh, etc.

    
por 27.03.2013 / 01:53
1

Seu comando está sendo interrompido às vezes por causa do recurso OpenSSH que impede que a sessão SSH feche até que todo o I / O aberto pelo processo em execução na sessão SSH seja fechado corretamente.

Uma maneira de evitar isso é redirecionar seus STDIN e STDOUT para algo diferente do terminal.

ssh $userAtServer "ls $targetDir/$targetFile > /dev/null < /dev/null 2>&1"

# lsReturnValue=$?

Se você precisar do STDOUT / STDERR do comando, você pode redirecioná-lo para um arquivo e depois cat-lo

ssh $userAtServer "ls $targetDir/$targetFile > /tmp/ls_output < /dev/null 2>&1;cat /tmp/ls_output"

    
por 26.03.2013 / 04:34

Tags