PAYATHON 2026

Bash 如何在空闲超时后重启 Firefox,避免每秒打开新标签页?

数据小许

需要修正空闲时间的比较方式,并确保脚本启动的 Firefox 实例可以跟踪生命周期。原来的 if($(xprintidle)>120000); 没有进行数值比较;每秒出现一个新标签页,通常与 Firefox 将启动请求转交给已有实例有关。

空闲时间判断为什么不正确

原来的写法是:

if($(xprintidle)>120000);

单层圆括号表示子 shell,$(xprintidle) 的输出会被当成命令名,而 >120000 是输出重定向,可能在当前目录创建名为 120000 的文件。

应先读取空闲时间,再使用 Bash 的算术比较:

idle=$(xprintidle)
if (( idle > 120000 )); then
    # 执行超时操作
    :
fi

xprintidle 返回的单位是毫秒,120000 对应 120 秒。实际使用时还应检查命令是否执行成功,以及输出是否为数字。

为什么会每秒打开一个标签页

第一个循环依赖一个前提:执行 firefox ... 后,该命令会一直等待浏览器退出。

如果启动请求被转交给已经运行的 Firefox 实例,新执行的命令可能很快返回。循环等待一秒后再次执行启动命令,就会不断向已有实例发送打开网址的请求。

仅凭提供的代码,无法确定为什么加入第二个循环后才出现这一现象。不过,第二个循环中的错误比较不能正确控制 Firefox 退出,需要单独修复。

对于 kiosk,可以使用专用 profile,并通过 --no-remote 避免将启动请求转交给已有实例。原命令中的其他参数需要根据实际 Firefox 版本确认是否适用,下面只保留相关启动参数。

用一个循环管理启动和超时

下面的示例会在 Firefox 退出后重新启动它,并在空闲达到 120 秒时关闭当前实例。在空闲时间降到阈值以下之前,脚本只触发一次关闭,避免无人操作时反复重启。

#!/usr/bin/env bash

url='https://thesite.com'
profile_dir="$HOME/.mozilla/firefox/kiosk-profile"
timeout_ms=120000
browser_pid=''
idle_handled=0

mkdir -p "$profile_dir" || exit 1

cleanup() {
    if [[ -n "$browser_pid" ]]; then
        kill "$browser_pid" 2>/dev/null || :
        wait "$browser_pid" 2>/dev/null || :
    fi
}

trap cleanup EXIT
trap 'exit 0' INT TERM

while true; do
    if [[ -z "$browser_pid" ]] || ! kill -0 "$browser_pid" 2>/dev/null; then
        if [[ -n "$browser_pid" ]]; then
            wait "$browser_pid" 2>/dev/null || :
        fi

        firefox --no-remote --profile "$profile_dir" --kiosk "$url" &
        browser_pid=$!
    fi

    if ! idle=$(xprintidle); then
        printf '%s\n' '无法读取空闲时间' >&2
        exit 1
    fi

    if [[ ! "$idle" =~ ^[0-9]+$ ]]; then
        printf '无效的空闲时间:%s\n' "$idle" >&2
        exit 1
    fi

    if (( 10#$idle < timeout_ms )); then
        idle_handled=0
    elif (( idle_handled == 0 )); then
        kill "$browser_pid" 2>/dev/null || :
        wait "$browser_pid" 2>/dev/null || :
        browser_pid=''
        idle_handled=1
    fi

    sleep 1
done

把 url 替换为实际网站地址,再用 Bash 运行脚本。$! 保存本次后台启动命令的 PID;关闭时只处理这个 PID。wait 等待该进程退出,下一轮循环再启动 Firefox。

这里使用 kill 默认发送的 SIGTERM 请求退出。如果 Firefox 卡住、没有响应,wait 可能持续等待。需要自动处理这种情况时,应另外设计退出超时和后续处理策略。

运行前需要注意什么

  • 专用 profile 不能同时被另一个 Firefox 实例占用。如果启动命令立即退出,先查看终端中的错误信息,确认参数、profile 和显示环境是否正常。
  • 原来的 pkill -f firefox 按完整命令行匹配,可能影响其他 Firefox 实例或相关进程。跟踪本次启动的 PID 更适合这个场景。
  • 原来的 sleep 120 只会暂停空闲检查循环,不会阻止另一个循环启动 Firefox。示例通过 idle_handled 控制连续空闲期间的重复触发。
  • 该方案以 xprintidle 能在当前 X11 会话中正常读取空闲时间为前提。原生 Wayland 环境需要使用适合桌面环境的空闲检测方式。

备注:内容仅供参考。