如何将服务器多目录txt文件按原有层级批量复制到本地
问题背景
抱歉若标题表述存在歧义。服务器上存储了多性状、多轮分析运行生成的大量文件,目录结构示例如下:
/Weight/run1/file1.txt
/Weight/run1/file2.txt
/Weight/run2/file1.txt
/Weight/run2/file2.txt
/LegLength/run1/file1.txt
/LegLength/run1/file2.txt
/LegLength/run2/file1.txt
/LegLength/run2/file2.txt
现有文件规模:共11个性状目录,每个性状对应2轮分析运行,每轮运行生成26个txt格式文件。需求为将所有txt文件复制到本地机器,同时保留原有文件层级结构,不需要复制叶子目录下其他扩展名的文件。
现有问题代码
参考公开方案拼凑的代码如下,运行时会错误尝试在服务器端查找本地路径~/Documents/path/to/local/directories,无法正常执行:
ssh user@server 'for f in /path/to/server/directories/*/*/*txt ; do newpath="${f%/*}"; newpath=${newpath:41} ; scp user@server:${f} ~/Documents/path/to/local/directories/${newpath}; done'
补充说明:代码中newpath=${newpath:41}的作用是移除变量中前缀路径/path/to/server/directories/
报错原因
整个for循环通过ssh提交到远程服务器执行,循环内的scp命令也运行在服务器环境中,服务器无法识别本地机器的路径,因此触发路径不存在的错误。
解决方案
以下两种方案均会完整保留原有的性状目录/分析轮次/目标文件层级结构,不会将多目录文件合并到单目录,同时自动过滤非txt格式的文件。
方案1:本地执行scp循环(无额外依赖,通用性强)
直接在本地终端运行以下代码,将开头的配置变量替换为自己的实际信息即可,不需要手动计算路径截取长度,适配任意长度的基础路径:
# 配置项,替换为自己的实际信息 REMOTE_BASE="/path/to/server/directories" LOCAL_BASE="$HOME/Documents/path/to/local/directories" REMOTE_USER="user" REMOTE_HOST="server" # 拉取远程所有txt文件的相对路径,逐文件创建目录后复制 while IFS= read -r rel_path; do rel_dir=$(dirname "$rel_path") mkdir -p "$LOCAL_BASE/$rel_dir" scp "$REMOTE_USER@$REMOTE_HOST:$REMOTE_BASE/$rel_path" "$LOCAL_BASE/$rel_path" done < <(ssh $REMOTE_USER@$REMOTE_HOST "find $REMOTE_BASE -type f -name '*.txt' | sed \"s|^$REMOTE_BASE/||\"")
方案2:rsync一键同步(效率更高,操作简单)
如果本地和服务器都安装了rsync,直接执行一行命令即可完成同步,传输效率比scp更高,支持断点续传:
rsync -av --include='*/' --include='*.txt' --exclude='*' user@server:/path/to/server/directories/ ~/Documents/path/to/local/directories/
参数说明:
-av:归档模式递归复制,保留文件原有属性,同时输出复制日志方便排查--include='*/':允许遍历所有层级的子目录,避免遗漏深层位置的txt文件--include='*.txt':匹配所有txt后缀的文件,纳入复制范围--exclude='*':排除其余所有未被纳入复制范围的文件
内容的提问来源于stack exchange,提问作者cjames

