Bash 迭代复制分散指定文件并完整保留原目录层级
关于cp写法的可行性判断
首先明确:你提到的cp $folder/difusion/Deterministic/$dti /media/Roy/Analysis/Patients/ --verbose 这类写法完全无法实现保留目录层级的需求。cp命令本身的默认行为是将匹配到的源文件直接放置到指定的目标目录根下,不会自动根据源文件的相对路径创建对应子目录,所有同名文件依然会发生覆盖,最终只会留存最后一次拷贝的文件。
可实现需求的正确方案
方案一:使用rsync精准筛选(最适配当前场景)
这种方案无需写复杂的循环逻辑,天然支持"仅拷贝指定文件、保留完整路径层级、跳过所有无关文件"的需求,对后续目录新增被试、调整层级的场景兼容性最强。
执行参考命令:
# 定义源、目标基准路径 SRC_BASE="/media/Batty/Analysis" DST_BASE="/media/Roy/Analysis" rsync -av \ --include='*/' \ --include='dti_fin_fa.nii' \ --exclude='*' \ "$SRC_BASE/Controls/" "$DST_BASE/Controls/"
参数说明:
-a开启归档模式,自动保留文件权限、时间戳等属性,递归遍历所有子目录--include='*/'允许遍历所有层级的子目录,确保完整的路径映射关系生效--include='dti_fin_fa.nii'标记所有名为dti_fin_fa.nii的文件为需要拷贝的对象--exclude='*'除了上述标记为需要拷贝的文件、以及维持路径必须的空目录层级外,其余所有无关文件全部跳过- 源路径末尾的斜杠
Controls/表示拷贝Controls目录内部的内容,不会额外嵌套多余的目录层级
方案二:基于原有bash循环逻辑修改
如果更习惯使用原有循环逻辑完成操作,只需补充相对路径计算、目标目录创建的步骤,即可实现预期效果,修改后的脚本如下:
#!/bin/bash DIR="/media/Batty/Analysis" DST_ROOT="/media/Roy/Analysis/Controls" cd "$DIR" || exit for group in Controls; do # 遍历每个被试的顶层文件夹(C01/C02/C03) for subject_dir in $group/*/; do # 定位需要拷贝的目标文件 target_file="${subject_dir}difusion/Deterministic/dti_fin_fa.nii" # 跳过不存在的文件,避免无效报错 [ -f "$target_file" ] || continue # 计算目标文件对应的完整存放路径 relative_path="${target_file#$DIR/}" full_dst_path="${DST_ROOT}/${relative_path}" # 提前创建目标文件对应的全部上级目录 mkdir -p "$(dirname "$full_dst_path")" # 执行拷贝并打印详细日志 cp -v "$target_file" "$full_dst_path" done done
脚本核心修改逻辑:
- 不再将所有文件直接拷贝到Controls根目录,而是通过截取源文件的相对路径,精准匹配每个文件在目标位置下的存放位置
- 通过
mkdir -p自动创建缺失的子目录层级,避免文件平铺覆盖的问题 - 增加文件存在性判断,遇到空目录、缺文件的场景不会产生大量无意义的错误提示
内容的提问来源于stack exchange,提问作者RoyBatty
相关产品推荐
相关产品推荐

