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

使用scp和mv跨服务器复制文件时出现文件丢失的问题求助

问题原因分析

你的脚本存在几个关键问题导致文件丢失:

  • 多文件时间监控失效:用stat -c %Z /mnt/deliverFiles/*.txt时,若目录下有多个.txt文件,命令会输出每个文件的修改时间,但赋值给变量时只会保留最后一个文件的时间。如果前面的文件更新而最后一个未变,脚本会错过处理这些文件。
  • 通配符展开时序问题:scp *.txt和mv *.txt的通配符是由shell提前展开的。若在scp执行过程中有新文件传入目录,mv会包含这些新文件,但scp并未传输它们,导致这些文件被移动但未同步到远程服务器。
  • 无错误校验:如果scp传输失败(比如网络中断),mv依然会执行,源文件被移走但远程服务器未收到,直接造成文件丢失。
  • 可能处理不完整文件:当文件正在被写入时,stat的修改时间会变化,脚本会触发操作,但此时文件可能还未写入完成,scp得到的是不完整的文件,后续mv会把这个不完整文件移走。
解决方案

推荐两种改进方案,优先选择基于inotify的实时监控方案,更高效可靠。

方案1:用inotifywait实时监控(推荐)

利用inotify机制监听目录的文件创建/移动事件,确保只处理完整传入的文件,且逐个处理避免遗漏:

#!/bin/bash
SOURCE_DIR="/mnt/deliverFiles"
TARGET_REMOTE="server:/home/files/"
LOCAL_ARCHIVE="/home/files"
TEMP_DIR="/mnt/deliverFiles/.processing"

# 创建临时处理目录,避免干扰新传入文件
mkdir -p "$TEMP_DIR"

# 监听目录的文件创建、移动完成事件(确保文件写入完毕)
inotifywait -m -e create,moved_to --format "%f" "$SOURCE_DIR" | while read FILENAME
do
    # 仅处理txt文件
    if [[ "$FILENAME" =~ \.txt$ ]]; then
        # 原子移动到临时目录,避免后续操作冲突
        mv "$SOURCE_DIR/$FILENAME" "$TEMP_DIR/"
        
        # 传输到远程服务器,校验执行结果
        if scp -p "$TEMP_DIR/$FILENAME" "$TARGET_REMOTE"; then
            # 传输成功后归档到本地目录
            mv "$TEMP_DIR/$FILENAME" "$LOCAL_ARCHIVE/"
            echo "Successfully processed $FILENAME"
        else
            # 传输失败,将文件移回原目录等待重试
            mv "$TEMP_DIR/$FILENAME" "$SOURCE_DIR/"
            echo "Failed to transfer $FILENAME, moved back to source"
        fi
    fi
done

优势

  • 实时响应文件传入,无需轮询等待
  • 原子移动文件到临时目录,确保处理的是完整文件
  • 单个文件单独处理,传输失败可自动重试
  • 避免通配符展开导致的遗漏问题

方案2:改进轮询脚本(无inotify时使用)

如果系统无法安装inotify-tools,可修改轮询逻辑,先将所有待处理文件转移到临时目录再处理:

#!/bin/bash
SOURCE_DIR="/mnt/deliverFiles"
TARGET_REMOTE="server:/home/files/"
LOCAL_ARCHIVE="/home/files"
TEMP_DIR="/mnt/deliverFiles/.processing"

mkdir -p "$TEMP_DIR"

while true
do
    # 先将所有源目录的txt文件移到临时目录(原子操作,避免新文件干扰)
    for FILE in "$SOURCE_DIR"/*.txt; do
        # 防止通配符无匹配时的空值
        [[ -f "$FILE" ]] || continue
        mv "$FILE" "$TEMP_DIR/"
    done

    # 处理临时目录中的文件
    for PROCESS_FILE in "$TEMP_DIR"/*.txt; do
        [[ -f "$PROCESS_FILE" ]] || continue
        FILENAME=$(basename "$PROCESS_FILE")
        
        if scp -p "$PROCESS_FILE" "$TARGET_REMOTE"; then
            mv "$PROCESS_FILE" "$LOCAL_ARCHIVE/"
            echo "Processed $FILENAME"
        else
            # 失败则移回原目录,下次轮询重试
            mv "$PROCESS_FILE" "$SOURCE_DIR/"
            echo "Transfer failed for $FILENAME, will retry"
        fi
    done

    sleep 5
done

优势

  • 避免原脚本中多文件时间监控的缺陷
  • 批量转移文件到临时目录,确保本次处理的文件不会被新传入文件干扰
  • 保留错误重试机制,防止传输失败导致的文件丢失

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 01:45:00