You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

编写Bash脚本等待远程进程结束,为何无法进入while循环?

远程进程等待Spinner动画无法进入循环的问题解决

我正在编写一个自动化任务脚本,其中一个步骤是等待远程机器上启动的进程执行完毕。我想在进程运行时显示一个Spinner加载动画,参考了本地进程等待的实现思路。

相关代码如下:

spinner_wait_remote() {

    local pid=$1
    local msg=${2-Process $pid still running}
    local spin='-\|/'
    local i=0
    while ssh "$remote_machine" "kill -0 $pid" 2>/dev/null
    do
        local i=$(( (i+1) %4 ))
        printf "\r${spin:$i:1} $msg"
        sleep .1
    done
    printf "\n\e[A\e[K"
}

问题在于,即使远程机器上存在指定的$pid,脚本也始终无法进入while循环。我有一个用于等待本地进程的类似方法运行正常,唯一区别是while条件中的ssh命令。

我还尝试将整个while循环放在远程机器上执行,但依然无法进入循环:

spinner_wait_remote() {

    pid=$1
    msg=${2-Process $pid still running}
    ssh "$remote_server" "
        spin='-\|/'
        i=0
        while kill -0 $pid 2>/dev/null
        do
            i=$(( (i+1) %4 ))
            printf \\\"\r${spin:$i:1} $msg\\\\"
            sleep .1
        done
        printf \\\"\n\e[A\e[K\\\\"
    "
}

问题原因及修复方案

第一个版本的问题

第一个脚本的核心问题是错误重定向的位置不对,且未确保远程kill -0的退出码正确传递:

  • 2>/dev/null是对本地ssh命令的错误输出重定向,远程机器上kill -0 $pid的错误输出仍会传回本地
  • 若远程执行kill -0返回非0(比如ssh用户无权限查看目标进程),ssh会将该退出码传回本地,导致while循环条件不成立

修复后的代码:

spinner_wait_remote() {
    local pid=$1
    local msg=${2-Process $pid still running}
    local spin='-\|/'
    local i=0
    # 将错误重定向放到远程命令内部,确保kill -0的错误被远程丢弃
    while ssh "$remote_machine" "kill -0 $pid 2>/dev/null"
    do
        i=$(( (i+1) %4 ))
        printf "\r${spin:$i:1} $msg"
        sleep .1
    done
    printf "\n\e[A\e[K"
}

额外检查项:

  • 确认$remote_machine变量已在函数外部正确定义
  • 手动执行ssh $remote_machine kill -0 $pid测试,返回0说明进程存在且当前ssh用户有权限查看

第二个版本的问题

第二个脚本的核心问题是本地shell提前展开了远程脚本中的变量和算术表达式:

  • 远程脚本中的${spin:$i:1}会被本地shell尝试展开(本地无spin变量,会变为空值)
  • i=$(( (i+1) %4 ))的算术计算会在本地完成,而非远程机器上执行
  • 双引号的转义处理容易出错,导致输出格式异常

修复后的代码:

spinner_wait_remote() {
    local pid=$1
    local msg=${2-Process $pid still running}
    # 用单引号包裹远程脚本,避免本地shell解析远程变量
    # 通过ssh命令行参数传递本地变量到远程
    ssh "$remote_server" '
        pid="$1"
        msg="$2"
        spin='\''-\|/'\''
        i=0
        while kill -0 "$pid" 2>/dev/null
        do
            i=$(( (i+1) %4 ))
            printf "\r${spin:$i:1} $msg"
            sleep .1
        done
        printf "\n\e[A\e[K"
    ' "$pid" "$msg"
}

这里通过ssh的命令行参数将本地的$pid和$msg传递到远程,远程脚本用$1、$2接收,同时用转义单引号定义spin变量,避免本地解析干扰。


内容的提问来源于stack exchange,提问作者Trilok Bhattacharya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 08:05:01