You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无inotify环境下目录变更检测Bash脚本及优化征询

受限环境目录毫秒级变更检测脚本优化方案

针对脚本现有问题和你提出的优化诉求,整理可直接落地的优化点如下:

1. 输入校验逻辑优化

你提到无法合并的秒数范围判断,直接在[[ ]]判断结构中使用逻辑或||即可单条语句覆盖两个边界条件,同时补充输入内容的纯数字校验,避免用户输入非数字内容导致脚本运行报错:

# 校验检测时长输入是否为纯数字
if ! [[ $seconds =~ ^[0-9]+$ ]]; then
    echo "检测时长必须为纯数字,脚本退出"
    exit 1
fi
# 单条判断覆盖时长上下限,无需拆分两个分支
if [[ $seconds -lt 10 || $seconds -gt 6000 ]]; then
    echo "检测时长必须在10秒到6000秒(1小时)区间内,脚本退出"
    exit 1
fi

目录校验部分补充读取权限判断,避免无目录读权限时后续ls命令执行失败。

2. 性能与逻辑bug修复

  • 修正原脚本删除检测部分的路径错误:原代码中sdiff -w 400 -s $temp1 /$temp2多写了根路径斜杠,会导致临时文件寻址失败,删除事件检测完全失效
  • 合并重复的sed调用:原逻辑中同一处理流程反复调用6-7次sed,每次管道调用都会fork独立进程,在毫秒级轮询的场景下性能损耗极高,可将所有sed规则合并为单次调用,大幅减少进程创建开销
  • 优化轮询逻辑:原循环中每次比对都执行cat $temp1读取磁盘文件,可在循环启动前把初始目录状态存为变量,减少无意义的磁盘IO
  • 修正文案与拼写错误:原删除事件提示语“File has removed modified”语义混乱,统一调整为准确的事件提示;修正拼写错误Exceded为Exceeded
  • 临时文件安全优化:原脚本使用固定临时文件名,会导致多实例同时运行时互相覆盖文件,改用mktemp生成随机临时目录,通过trap配置脚本退出时自动清理,避免残留文件冲突
  • 所有变量统一加双引号包裹,兼容带空格、特殊字符的目录路径
  • 替换低效的行数统计判断:原逻辑用grep | wc -l判断匹配结果是否存在,替换为grep -q,匹配到内容后直接退出,无需统计全量行数,执行效率更高

3. 优化后完整脚本

#!/bin/bash
# Directory Check Script
# 适配无inotify权限的受限环境,支持毫秒级目录变更检测
# Created 13 Aug 2022, optimized version

# 生成随机临时目录,配置脚本退出自动清理
tmp_dir=$(mktemp -d)
trap 'rm -rf "$tmp_dir"' EXIT
temp1="$tmp_dir/temp1.txt"
temp2="$tmp_dir/temp2.txt"

echo "本脚本将在指定时长内检测目标目录的文件变更(新增/修改/删除)"

read -ep '请输入要检测的完整目录路径: ' dir
if [ ! -d "$dir" ] || [ ! -r "$dir" ]; then
    echo "目录不存在或无读取权限,脚本退出"
    exit 1
fi

read -ep '请输入检测时长(范围10-6000秒,例如5分钟填300、1小时填6000): ' seconds
# 校验输入为纯数字
if ! [[ $seconds =~ ^[0-9]+$ ]]; then
    echo "检测时长必须为纯数字,脚本退出"
    exit 1
fi
# 单条判断覆盖时长上下限
if [[ $seconds -lt 10 || $seconds -gt 6000 ]]; then
    echo "检测时长必须在10到6000秒区间内,脚本退出"
    exit 1
fi

echo "开始检测目录 $dir,检测时长 $seconds 秒"
# 缓存初始目录状态,避免循环中反复读磁盘
ls --full-time "$dir" | tail -n +2 > "$temp1"
initial_state=$(cat "$temp1")

SECONDS=0
echo "每0.001秒轮询一次目录状态,检测中..."
until [[ $(ls --full-time "$dir" | tail -n +2) != "$initial_state" ]] > /dev/null 2>&1
do
    if (( SECONDS > seconds )); then
        echo "已达到设定检测时长 $seconds 秒,未检测到变更,脚本退出"
        exit 0
    fi
    sleep 0.001
done

# 捕获变更后状态
ls --full-time "$dir" | tail -n +2 > "$temp2"
diff_result=$(sdiff -w 400 -s "$temp1" "$temp2")

# 检测修改事件,合并sed规则为单次调用
if echo "$diff_result" | grep -q " |"; then
    echo -e "\n检测到目录 $dir 下文件被修改:"
    echo "$diff_result" | grep " |" | sed -e 's/|/\n/' \
        -e 's/^[ \t]*//g' \
        -e '1i 变更前:' \
        -e '3i 变更后:'
fi

# 检测新增事件
if echo "$diff_result" | grep -q " >"; then
    echo -e "\n检测到目录 $dir 下有新增文件:"
    echo "$diff_result" | grep " >" | sed -e 's/>//' \
        -e 's/^[ \t]*//g' \
        -e 's/[ \t]*$//g' \
        -e '/./!d' \
        -e 's/^/新增文件: /'
fi

# 检测删除事件,修正原路径错误
if echo "$diff_result" | grep -q " <"; then
    echo -e "\n检测到目录 $dir 下有文件被删除:"
    echo "$diff_result" | grep " <" | sed -e 's/<//' \
        -e 's/^[ \t]*//g' \
        -e 's/[ \t]*$//g' \
        -e '/./!d' \
        -e 's/^/删除文件: /'
fi

exit 0

补充说明

原轮询逻辑中ls --full-time会读取文件的修改时间、大小等元数据,对于仅存在数毫秒的临时文件,只要文件创建时完成了目录项写入,1ms的轮询间隔完全可以捕获到。如果后续需要进一步提升检测精度,可以把sleep时长调小到0.0005秒,但要注意过高的轮询频率会增加CPU占用,1ms间隔在大多数受限环境场景下已经足够覆盖毫秒级临时文件的检测需求。

内容的提问来源于stack exchange,提问作者Musik847

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 11:36:21