异步进程的退出状态

异步进程的退出状态

尽管以下命令返回取决于远程文件是否存在的退出状态:

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

然后我可以测试做一些事情,它有时挂起(十分之一或 20)并阻止进一步的代码执行。

所以我需要运行一个像这样的 ssh 命令并检索 ls 函数的退出值:

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

但是,lsReturnValue 始终返回空字符串。

timeOutProcess 是一个函数,如果命令持续时间过长,它会终止我的命令:

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  
}

我想知道我怎样才能得到$? ssh 命令的值?

答案1

您可以通过两种方式使用标准 shell 功能获取进程的返回状态ssh:同步运行它,或者调用wait内置函数。当你跑步时

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

这只lsReturnValue在子 shell 中设置,除了返回父 shell 的返回状态之外,您无法获取任何信息。因此,您必须exit $lsReturnValue从子 shell 运行并从父 shell 获取子 shell 的返回状态;然后整个后台过程可以简化为ssh $userAtServer "ls $targetDir/$targetFile" > $sshOutputFile &无论如何。

您发现允许命令超时的这个 shell 片段并不是一个很好的片段,因为它不保留返回状态。在 Linux 上,使用timeout公用事业。

如果没有timeout实用程序,事情就会变得有点棘手。您需要运行两个子进程:一个是您感兴趣的子进程,另一个是sleep针对超时部分运行的子进程。如果任一进程返回,它必须杀死另一个进程并允许 shell 继续执行。不幸的是,wait当您不带参数调用它时,内置函数会等待所有子进程都终止。同步两个进程的一种方法是让它们都写入管道,并在管道上出现一些数据时终止它们。

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

如果您要向多个服务器发送命令,请认真考虑使用ssh多服务器框架例如 mussh、clustersh 等。

答案2

您的命令有时会被挂起,因为 OpenSSH 功能会阻止 SSH 会话关闭,直到 SSH 会话中运行的进程打开的所有 IO 都正确关闭为止。

防止这种情况的一种方法是将 STDIN 和 STDOUT 重定向到终端以外的其他位置。

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

# lsReturnValue=$?

如果您需要命令的 STDOUT/STDERR,您可以将它们重定向到文件并稍后对其进行 cat

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

相关内容