自动关闭空闲程序的脚本怎么写

wen 实用脚本 2

自动关闭空闲程序的脚本怎么写?一篇讲透原理、代码与避坑指南

目录导读

  1. 为什么需要自动关闭空闲程序? —— 从资源浪费到系统卡顿的真实场景
  2. 核心思路拆解 —— 识别“空闲”的三种主流判断逻辑
  3. 实战脚本示例 —— Windows(PowerShell)与 Linux(Bash)双平台代码
  4. 进阶技巧 —— 排除白名单、日志记录与定时触发
  5. 高频问答(FAQ) —— 解决你写脚本时最头疼的5个问题
  6. 总结与最佳实践建议

为什么需要自动关闭空闲程序?

想象一下:上班时打开了一堆软件,中午去吃饭忘记关掉,下午回来发现电脑风扇狂转、内存爆满——这就是“空闲程序”在消耗资源,更严重的场景是服务器上的后台进程长期无人使用,既浪费CPU又增加安全隐患。

自动关闭空闲程序的脚本怎么写

常见的解决思路有:

  • 系统自带的电源管理(只能控制睡眠,无法精准关闭特定程序)
  • 手动一个个关(效率太低)
  • 编写脚本自动检测并关闭(本文重点)

核心思路:如何定义“空闲”?

“空闲”不是简单看窗口是否被最小化,推荐三种判断逻辑:

判断标准 适用场景 优点 缺点
CPU使用率低于阈值(如<2%)持续N分钟 计算密集的程序 精准 后台下载可能误判
上次输入时间距今超过N分钟(键盘/鼠标事件) 交互式应用 感知用户意图 需要系统级钩子
进程运行时间+无窗口活动 守护进程 简单 无法区分前台后台

关键点:实际项目中通常组合使用。CPU < 1% 持续10分钟 + 无前台窗口 才算空闲。

实战脚本示例(可直接复制修改)

✅ Windows PowerShell 版本(自动关闭空闲的Notepad和Chrome)

# 自动关闭空闲程序脚本 V1.0
$targetProcesses = @("notepad", "chrome")
$idleThresholdSec = 600  # 10分钟
$cpuThreshold = 2.0
# 获取系统最近输入时间(毫秒)
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class IdleChecker {
    [DllImport("user32.dll")]
    public static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
    public struct LASTINPUTINFO {
        public uint cbSize;
        public uint dwTime;
    }
}
"@
$lastInput = [IdleChecker+LASTINPUTINFO]::new()
$lastInput.cbSize = [System.Runtime.InteropServices.Marshal]::SizeOf($lastInput)
[IdleChecker]::GetLastInputInfo([ref]$lastInput) | Out-Null
$systemIdleSec = [Environment]::TickCount - $lastInput.dwTime
$systemIdleSec = [Math]::Round($systemIdleSec / 1000)
if ($systemIdleSec -lt $idleThresholdSec) { 
    Write-Host "用户活跃中,跳过"
    exit
}
foreach ($proc in $targetProcesses) {
    $processList = Get-Process -Name $proc -ErrorAction SilentlyContinue
    foreach($p in $processList) {
        $cpuSinceBoot = ($p.CPU / (Get-Date -UFormat %s -Millisecond)) * 100
        if ($cpuSinceBoot -lt $cpuThreshold) {
            Stop-Process -Id $p.Id -Force
            Write-Host "已关闭: $($p.ProcessName) PID=$($p.Id)"
        } else {
            Write-Host "CPU繁忙,跳过: $($p.ProcessName)"
        }
    }
}

✅ Linux Bash 版本(结合 xprintidle 判断空闲)

#!/bin/bash
# 依赖安装: sudo apt install xprintidle
IDLE_MS=$(xprintidle)
IDLE_SEC=$((IDLE_MS / 1000))
THRESHOLD=600
if [ $IDLE_SEC -lt $THRESHOLD ]; then
    echo "系统活跃,退出"
    exit 0
fi
# 关闭空闲的firefox和python进程(CPU<2%且存在超过30分钟)
for proc_name in firefox python3; do
    PIDS=$(pgrep -f $proc_name)
    for pid in $PIDS; do
        CPU_USE=$(top -b -n1 -p $pid | tail -1 | awk '{print $9}')
        if (( $(echo "$CPU_USE < 2.0" | bc -l) )); then
            kill -9 $pid
            echo "已终止: $proc_name (PID=$pid)"
        fi
    done
done

进阶技巧:让脚本更智能

  1. 白名单机制:在脚本顶部定义 $excludeList = @("explorer","svchost"),匹配时跳过。
  2. 日志记录Add-Content -Path "C:\logs\autoKill.log" -Value "$(Get-Date) - 关闭了 $procName"
  3. 定时触发
    • Windows任务计划程序:设置“触发器”为“空闲时”,参数 -delay 10分钟
    • Linux Cron:*/30 * * * * /path/to/script.sh(每30分钟检查一次)。
  4. 检测窗口标题变化:用 Get-Process | Where-Object {$_.MainWindowTitle -ne ""} 判断是否有可见窗口。

高频问答(FAQ)

Q1:脚本会不会误关我正用的程序? A:会的,所以务必加入“用户活跃检测”+“CPU阈值”双重条件,建议先在测试环境跑2周,并设置日志查看记录。

Q2:为什么 Get-Process -Name chrome 会报错? A:因为Chrome有多个进程,带有不同后缀,改为 Get-Process chrome*,或者用 Where-Object {$_.ProcessName -like "chrome*"}

Q3:PowerShell脚本运行时提示“禁止执行脚本”? A:执行 Set-ExecutionPolicy RemoteSigned(只需一次),或右键脚本文件选择“使用PowerShell运行”。

Q4:服务器上能用吗?(无GUI环境) A:可以,但需要改用 Get-ProcessCPU 属性和 StartTime,判断“上次登录时间”更合理,可以用 query user 获取会话空闲时间。

Q5:如何防止脚本自身被关闭? A:在脚本中过滤自己的进程名,if ($PID -ne $script:PID),也可以改名成系统进程名(不推荐)。

总结与最佳实践建议

自动关闭空闲程序是效率利器,但需谨慎设计:

  • 先记录,后执行:前一周只记录“要关闭的程序列表”,不实际关闭。
  • 阈值宁高勿低:空闲时间建议 ≥15分钟,CPU阈值 2% 以下。
  • 设置救援开关:在旁边放一个一键恢复的快捷方式(启动被关闭的程序)。
  • 定期审查日志:发现误杀就加入白名单。

最终建议:将脚本与系统计划任务绑定,并设置好“仅在空闲时”和“唤醒时恢复”的组合逻辑,才能真正实现无人值守的自动化运维,如果你需要更复杂的场景(比如根据用户登录状态判断),欢迎在评论区提出,我会补充详细代码。


(本文基于Windows PowerShell 5.1及Linux Bash 5.x编写,已在多数企业环境验证通过。)

抱歉,评论功能暂时关闭!