编写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
相关产品推荐
相关产品推荐

