本文目录导读:

#!/bin/bash
# 不活跃阈值(秒)
INACTIVE_LIMIT=300 # 5分钟
CHECK_INTERVAL=60 # 检查间隔(秒)
# 需要监控的程序列表(进程名或完整路径)
TARGET_PROGRAMS=(
"firefox"
"google-chrome"
"code" # VS Code
)
# 获取当前活跃窗口的进程信息
get_active_process() {
# 方法1:使用xdotool(需要安装)
if command -v xdotool &> /dev/null; then
active_pid=$(xdotool getactivewindow getwindowpid)
if [ -n "$active_pid" ]; then
ps -p "$active_pid" -o comm= 2>/dev/null
return
fi
fi
# 方法2:使用wmctrl(备用方案)
if command -v wmctrl &> /dev/null; then
active_window=$(wmctrl -lp | grep "$(xdotool getactivewindow getwindowname)" | awk '{print $3}')
if [ -n "$active_window" ]; then
ps -p "$active_window" -o comm= 2>/dev/null
return
fi
fi
echo ""
}
# 获取进程的最后活动时间
get_last_active_time() {
local process_name=$1
# 使用/proc文件系统获取进程启动时间
local pids=$(pgrep -x "$process_name" 2>/dev/null)
if [ -n "$pids" ]; then
for pid in $pids; do
# 获取进程启动时间(Unix时间戳)
local start_time=$(stat -c %Y /proc/"$pid" 2>/dev/null)
# 获取进程的tty活动时间(如果有)
local last_access=$(stat -c %X /proc/"$pid" 2>/dev/null)
echo "$last_access"
return
done
fi
echo ""
}
# 主检查循环
echo "启动不活跃程序监控..."
echo "不活跃阈值:${INACTIVE_LIMIT}秒"
echo "检查间隔:${CHECK_INTERVAL}秒"
echo "监控程序:${TARGET_PROGRAMS[*]}"
echo "----------------------------------------"
while true; do
current_time=$(date +%s)
active_process=$(get_active_process)
for program in "${TARGET_PROGRAMS[@]}"; do
# 检查程序是否在运行
if pgrep -x "$program" &> /dev/null; then
# 获取程序最后活动时间
last_active=$(get_last_active_time "$program")
if [ -n "$last_active" ] && [ "$last_active" -gt 0 ]; then
inactive_time=$((current_time - last_active))
# 检查程序是否当前活跃(是活跃窗口)
if [ "$active_process" != "$program" ]; then
if [ "$inactive_time" -gt "$INACTIVE_LIMIT" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - 程序 $program 不活跃超过 ${INACTIVE_LIMIT}秒 (实际:${inactive_time}秒),正在终止..."
# 终止程序(使用SIGTERM先,如果不行再用SIGKILL)
pkill -x "$program" 2>/dev/null
sleep 2
# 如果进程仍然存在,强制终止
if pgrep -x "$program" &> /dev/null; then
pkill -9 -x "$program" 2>/dev/null
echo "$(date '+%Y-%m-%d %H:%M:%S') - 强制终止 $program"
else
echo "$(date '+%Y-%m-%d %H:%M:%S') - $program 已正常终止"
fi
fi
fi
fi
fi
done
sleep "$CHECK_INTERVAL"
done
安装和使用说明
安装依赖工具
# Debian/Ubuntu sudo apt-get install xdotool wmctrl # CentOS/RHEL sudo yum install xdotool wmctrl # macOS (使用brew) brew install xdotool
保存脚本
# 保存为文件 nano kill_inactive.sh # 添加执行权限 chmod +x kill_inactive.sh # 运行脚本 ./kill_inactive.sh
自定义配置
INACTIVE_LIMIT: 不活跃超时时间(秒)CHECK_INTERVAL: 检查间隔(秒)TARGET_PROGRAMS: 要监控的程序列表
替代方案:Python版本(更可靠)
#!/usr/bin/env python3
import os
import time
import subprocess
import json
from datetime import datetime
# 配置
INACTIVE_LIMIT = 300 # 5分钟
CHECK_INTERVAL = 60 # 1分钟
TARGET_PROGRAMS = ["firefox", "google-chrome", "code"]
def get_active_window_process():
"""获取当前活跃窗口的进程名"""
try:
# 使用xdotool获取活跃窗口PID
result = subprocess.run(
["xdotool", "getactivewindow", "getwindowpid"],
capture_output=True, text=True, timeout=2
)
if result.returncode == 0:
pid = result.stdout.strip()
# 获取进程名
proc_result = subprocess.run(
["ps", "-p", pid, "-o", "comm="],
capture_output=True, text=True, timeout=2
)
if proc_result.returncode == 0:
return proc_result.stdout.strip()
except:
pass
return None
def get_process_last_active(pid):
"""获取进程最后活动时间(文件访问时间)"""
try:
proc_dir = f"/proc/{pid}"
if os.path.exists(proc_dir):
# 使用进程的文件访问时间作为活动指示
stat_info = os.stat(proc_dir)
return stat_info.st_atime
except:
pass
return None
def kill_process(process_name):
"""终止进程"""
try:
# 先尝试正常终止
subprocess.run(["pkill", "-x", process_name], timeout=5)
time.sleep(2)
# 检查是否还在运行,强制终止
check = subprocess.run(
["pgrep", "-x", process_name],
capture_output=True, text=True
)
if check.stdout.strip():
subprocess.run(["pkill", "-9", "-x", process_name], timeout=5)
return "force_killed"
return "killed"
except Exception as e:
return f"error: {e}"
def main():
print(f"启动不活跃程序监控...")
print(f"不活跃阈值:{INACTIVE_LIMIT}秒")
print(f"检查间隔:{CHECK_INTERVAL}秒")
print(f"监控程序:{TARGET_PROGRAMS}")
print("-" * 40)
while True:
try:
current_time = time.time()
active_process = get_active_window_process()
# 获取所有目标程序的PID
for program in TARGET_PROGRAMS:
result = subprocess.run(
["pgrep", "-x", program],
capture_output=True, text=True
)
pids = result.stdout.strip().split('\n') if result.stdout.strip() else []
for pid in pids:
if not pid:
continue
last_active = get_process_last_active(pid)
if last_active:
inactive_time = current_time - last_active
# 检查是否当前活跃
if active_process != program:
if inactive_time > INACTIVE_LIMIT:
print(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} - "
f"程序 {program} (PID: {pid}) 不活跃超过 "
f"{INACTIVE_LIMIT}秒 (实际:{int(inactive_time)}秒),终止中...")
status = kill_process(program)
print(f"状态:{status}")
break # 只终止一个实例
time.sleep(CHECK_INTERVAL)
except KeyboardInterrupt:
print("\n监控已停止")
break
except Exception as e:
print(f"错误:{e}")
time.sleep(CHECK_INTERVAL)
if __name__ == "__main__":
main()
注意事项
- x permission: 需要
xdotool访问X server,可能在Wayland下不工作 - 权限问题: 可能需要root权限来终止某些系统进程
- 准确性: 不活跃检测基于文件访问时间,可能不完全准确
- 资源占用: 监控会占用少量系统资源
自动启动(开机自启)
# 创建systemd服务(Linux) sudo nano /etc/systemd/system/kill_inactive.service [Unit] Description=Kill Inactive Programs Monitor [Service] ExecStart=/path/to/kill_inactive.sh Restart=always User=your_username [Install] WantedBy=default.target # 启用服务 sudo systemctl enable kill_inactive.service sudo systemctl start kill_inactive.service
选择适合你系统的版本,并根据需要调整配置参数。