Shell多后台进程运行时如何避免spinner动画输出互相干扰
问题根因
所有后台进程共享终端的同一光标位置,原spinner仅用\r回到当前行首,多进程同时输出时光标位置互相抢占,自然会出现行覆盖、内容串扰。
实现方案
给每个spinner预分配专属固定输出行,通过ANSI终端转义码控制光标移动到指定行更新内容,更新完成后把光标移回内容区末尾,彻底避免输出抢占。不需要额外安装工具,纯shell内置能力即可实现。
完整修改后代码
#!/bin/bash # 初始化终端格式、控制码 bold=$(tput bold) reset=$(tput sgr0) CLEAR_LINE="\033[2K" MOVE_UP_FMT="\033[%dA" MOVE_DOWN_FMT="\033[%dB" # 增强版spinner: 参数1=专属行距当前底部的偏移量, 参数2=显示文本 spinner(){ local offset=$1 local msg=$2 local move_up move_up=$(printf "$MOVE_UP_FMT" "$offset") local move_down move_down=$(printf "$MOVE_DOWN_FMT" "$offset") while :; do for s in / - \\ \|; do # 移动到专属行, 清空整行后输出spinner状态 printf "%s%s\r[%s] %s%s%s" "$move_up" "$CLEAR_LINE" "$s" "$bold" "$msg" "$reset" # 光标移回底部原位置, 避免抢占其他输出 printf "%s" "$move_down" sleep 0.2 done done } # 退出时自动清理所有后台进程, 避免残留乱码 trap 'kill $(jobs -p) 2>/dev/null; printf "\n所有任务执行结束\n"; exit' INT TERM EXIT ########## 预分配固定输出行 ########## echo "Start Function 1" echo "[ ] func1 running" # func1 spinner专属行 echo "Start Function 2" echo "[ ] func2 running" # func2 spinner专属行 echo "Start Function 3" echo "[ ] func3 running" # func3 spinner专属行 ####################################### func1(){ # 传入专属行偏移: 预分配完成后光标在第7行, func1 spinner在第2行, 需上移5行 spinner 5 "func1 running" & local spinner_pid=$! # 执行业务逻辑 sleep 20 # 杀掉spinner, 更新为完成状态 kill $spinner_pid printf "\033[5A${CLEAR_LINE}\r[✓] ${bold}func1 执行完成${reset}\033[5B" } func2(){ # func2 spinner在第4行, 需上移3行 spinner 3 "func2 running" & local spinner_pid=$! # 执行业务逻辑 sleep 30 kill $spinner_pid printf "\033[3A${CLEAR_LINE}\r[✓] ${bold}func2 执行完成${reset}\033[3B" } func3(){ # func3 spinner在第6行, 需上移1行 spinner 1 "func3 running" & local spinner_pid=$! # 执行业务逻辑 sleep 50 kill $spinner_pid printf "\033[1A${CLEAR_LINE}\r[✓] ${bold}func3 执行完成${reset}\033[1B" } # 启动所有任务 func1& func2& func3 wait
注意事项
- 行偏移量根据预分配的行位置计算,新增业务函数时先在预分配区加对应提示行、spinner占位行,再按实际行数调整偏移值即可
- 业务逻辑中如果需要打印日志,不要直接用echo输出,否则会打乱终端行结构,可额外在最底部预留日志区做输出
- 方案兼容所有支持ANSI转义码的终端,包括主流Linux发行版默认终端、macOS Terminal、iTerm2、Windows Terminal等
内容的提问来源于stack exchange,提问作者Adham A. Makroum
相关产品推荐
相关产品推荐

