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

inotifywait未等待文件操作完成的魔兽3地图同步脚本问题

问题

通过Lutris安装Warcraft3后,编写了自动复制Downloads目录中自定义地图(*.w3x)到游戏地图目录的脚本。但遇到问题:inotifywait在下载的0字节文件刚创建时就触发复制操作,导致复制空文件却提示成功。

需要实现无需sleep的文件写入/下载/移动完成等待逻辑(无法预知文件大小和下载速度,不愿用sleep)。曾尝试监听close_write事件,但未解决问题——要么没等待文件关闭写入,要么下载操作不触发该事件。

原脚本如下:

#!/bin/bash

# 脚本启动后监听Downloads目录,发现*.w3x文件时,检查游戏地图目录是否存在该文件,不存在则复制并删除原文件

# 监听目录
DIR_TO_WATCH="$HOME/Downloads/"
# 目标目录
DEST_DIR="$HOME/Games/battlenet/drive_c/users/user/Documents/Warcraft III/Maps/Download/"

# 启动inotifywait监听close事件,管道传递给后续处理
inotifywait -m "$DIR_TO_WATCH" -e close |
while read path action file
do
    # 检查是否为War3地图文件
    if [[ "$file" == *.w3x ]];
    then
        # 检查目标目录是否已存在该文件
        if [ ! -f "$DEST_DIR/$file" ];
        then
            echo "NEW TRANSACTION ---$(date)---" >> wc3_mapsync.log
            echo "$(date) | $file size before copy: $(stat -c%s "$path$file")" >> wc3_mapsync.log
            cp "$path$file" "$DEST_DIR"
            if [ $? -eq 0 ]
            then    
                echo "$(date) | $file COPIED SUCCESSFULLY $path$file >>> $DEST_DIR" >> wc3_mapsync.log
                echo "$(date) | $file size after copy: $(stat -c%s "$DEST_DIR/$file")" >> wc3_mapsync.log
                echo "---END TRANSACTION---" >> wc3_mapsync.log
                rm "$path$file"
            else    
                echo "$(date) | $file COPY FAILED with exit status code $? '|' $path$file" >> wc3_mapsync.log
                echo "---END TRANSACTION---" >> wc3_mapsync.log
            fi
        else
            echo "$(date) | $file ALREADY EXISTS, copy would be duplicate."  >> wc3_mapsync.log
            echo "---END TRANSACTION---" >> wc3_mapsync.log
        fi
    else 
        :
    fi
done
解决方案

1. 调整监听事件组合

很多下载工具会先创建临时文件写入,完成后重命名/移动到Downloads目录;或者持续写入直到完成后关闭文件。因此需要同时监听close_write和moved_to事件,覆盖这两种场景:

inotifywait -m "$DIR_TO_WATCH" -e close_write,moved_to

2. 验证文件大小稳定

即使触发了上述事件,仍可能存在文件未完全写入的情况(比如某些工具的写入逻辑)。可以在触发事件后,循环检查文件大小,直到连续两次检查的大小一致,确认文件写入完成:

wait_for_file() {
    local file="$1"
    local prev_size=0
    local curr_size=$(stat -c%s "$file")
    while [ "$curr_size" -ne "$prev_size" ]; do
        prev_size="$curr_size"
        sleep 0.1  # 短间隔,不影响效率
        curr_size=$(stat -c%s "$file")
    done
}

3. 改进事件解析(可选)

使用--format参数让inotifywait输出更结构化的内容,避免read解析错误:

inotifywait -m "$DIR_TO_WATCH" -e close_write,moved_to --format '%w%f %e' |
while read full_path events
do
    file=$(basename "$full_path")
    # 后续处理逻辑
done

修改后的完整脚本

#!/bin/bash

# 脚本启动后监听Downloads目录,发现*.w3x文件时,检查游戏地图目录是否存在该文件,不存在则复制并删除原文件

# 监听目录
DIR_TO_WATCH="$HOME/Downloads/"
# 目标目录
DEST_DIR="$HOME/Games/battlenet/drive_c/users/user/Documents/Warcraft III/Maps/Download/"

# 等待文件写入完成的函数:检查文件大小稳定
wait_for_file() {
    local file="$1"
    if [ ! -f "$file" ]; then
        return 1
    fi
    local prev_size=0
    local curr_size=$(stat -c%s "$file")
    while [ "$curr_size" -ne "$prev_size" ]; do
        prev_size="$curr_size"
        sleep 0.1
        curr_size=$(stat -c%s "$file")
    done
}

# 启动inotifywait监听close_write和moved_to事件,结构化输出
inotifywait -m "$DIR_TO_WATCH" -e close_write,moved_to --format '%w%f %e' |
while read full_path events
do
    file=$(basename "$full_path")
    # 检查是否为War3地图文件
    if [[ "$file" == *.w3x ]];
    then
        # 等待文件完全写入
        if ! wait_for_file "$full_path"; then
            echo "$(date) | $file does not exist, skipping." >> wc3_mapsync.log
            echo "---END TRANSACTION---" >> wc3_mapsync.log
            continue
        fi

        # 检查目标目录是否已存在该文件
        if [ ! -f "$DEST_DIR/$file" ];
        then
            echo "NEW TRANSACTION ---$(date)---" >> wc3_mapsync.log
            echo "$(date) | $file size before copy: $(stat -c%s "$full_path")" >> wc3_mapsync.log
            cp "$full_path" "$DEST_DIR"
            if [ $? -eq 0 ]
            then    
                echo "$(date) | $file COPIED SUCCESSFULLY $full_path >>> $DEST_DIR" >> wc3_mapsync.log
                echo "$(date) | $file size after copy: $(stat -c%s "$DEST_DIR/$file")" >> wc3_mapsync.log
                echo "---END TRANSACTION---" >> wc3_mapsync.log
                rm "$full_path"
            else    
                echo "$(date) | $file COPY FAILED with exit status code $? '|' $full_path" >> wc3_mapsync.log
                echo "---END TRANSACTION---" >> wc3_mapsync.log
            fi
        else
            echo "$(date) | $file ALREADY EXISTS, copy would be duplicate."  >> wc3_mapsync.log
            echo "---END TRANSACTION---" >> wc3_mapsync.log
        fi
    fi
done

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 21:35:03