如何用分块实现文件流式传输到tar?SSH备份场景问题求助
问题分析与修复方案
你的核心需求是通过SSH流式备份远程主机内容(含目录和服务逻辑转储),但受限于远程主机磁盘空间,只能通过split分块临时存储转储内容,再交给tar归档后删除临时块。脚本的不稳定源于时序逻辑错误和事件监听不准确,以下是具体修复方案:
故障原因拆解
- tar进程挂起:原脚本用
close_nowrite触发文件删除,此时tar可能仍在读取已删除的文件(Linux下文件删除后,持有描述符的进程仍可读取),加上FIFO写端关闭时机与tar文件处理的时序冲突,导致tar无法正常接收EOF信号退出。 - 0字节文件条目:
close_nowrite事件在tee写完文件就触发,此时tar可能还未打开该文件,删除后tar尝试读取不存在的文件,最终生成0字节归档条目。
修复后的脚本
#!/bin/bash set -euo pipefail # 创建权限受限的FIFO,避免外部干扰 mkfifo -m 600 filenames # 启动tar进程,从FIFO读取待归档文件列表,输出到标准输出 tar --files-from filenames -cf - & TAR_PID=$! # 打开FIFO的写文件描述符 exec 100>filenames # 先添加主机级目录/文件到归档列表 echo "/etc" >&100 echo "/root" >&100 # 定义split过滤函数:处理转储分块,确保tar读完后再删除临时文件 splitfilter() { local temp_file="$1" # 将转储内容写入临时文件 tee "$temp_file" # 强制刷盘,确保内容完全写入磁盘 sync "$temp_file" # 向tar发送当前临时文件名,触发归档 echo "$temp_file" >&100 # 等待所有进程(含tar)关闭该文件后再删除 inotifywait -qq -e close "$temp_file" # 删除临时文件 rm -f "$temp_file" } # 导出函数,供split的子shell调用 export -f splitfilter # 执行服务逻辑转储,分块处理后传入归档流程 dump_program_1 | split -b 4K /var/backup/PREFIX_DUMP_1_ --filter 'splitfilter "$FILE"' dump_program_2 | split -b 4K /var/backup/PREFIX_DUMP_2_ --filter 'splitfilter "$FILE"' # 关闭FIFO写端,向tar发送EOF,告知无更多文件需要归档 exec 100>&- # 等待tar完成所有归档操作 wait $TAR_PID # 清理FIFO文件 rm -f filenames
关键修复点
- 调整事件监听逻辑:用
inotifywait -e close替代close_nowrite,只有当所有打开该文件的进程(包括tar)都关闭描述符后,才删除临时文件,彻底避免tar读取不完整或不存在的文件。 - 确保文件写入完整性:添加
sync命令强制刷盘,避免tar读取到未完全写入磁盘的内容。 - 严格模式开启:
set -euo pipefail提前捕获脚本中的错误(如变量未定义、命令执行失败),减少隐性问题。 - FIFO权限控制:
mkfifo -m 600限制FIFO的访问权限,防止外部进程意外写入干扰归档流程。 - 变量安全包裹:用引号包裹所有变量,避免文件名含特殊字符时出现解析错误。
内容的提问来源于stack exchange,提问作者Thysce
相关产品推荐
相关产品推荐

