如何用Bash脚本仅拼接文件名首下划线前ID相同的文件并归档原文件
同标识符文件批量拼接可运行Bash脚本
针对你的命名规则、拼接需求、归档逻辑,下面给出完全适配的脚本,无复杂外部依赖,对Bash新手友好:
完整可运行脚本
#!/bin/bash # 可自定义修改归档目录名称 archive_dir="original files" # 自动创建归档目录,已存在则不重复创建避免报错 mkdir -p "$archive_dir" # 声明关联数组用于按标识符归集文件 declare -A file_list # 遍历当前目录下所有待处理txt文件,跳过已生成的merged文件,支持带空格的文件名/目录名 while IFS= read -r -d '' file; do # 提取每个文件的唯一标识符:取第一个下划线前的所有字符串 filename=$(basename "$file") id=${filename%%_*} # 按标识符归集对应文件路径 file_list[$id]+="$file"$'\n' done < <(find . -maxdepth 1 -name "*.txt" ! -name "*_merged.txt" -print0) # 遍历所有归集好的标识符组 for id in "${!file_list[@]}"; do # 拆分出当前标识符下的所有文件 mapfile -t files <<< "${file_list[$id]}" file_count=${#files[@]} # 仅当同标识符下文件数≥2时执行拼接 if [ "$file_count" -gt 1 ]; then echo "处理标识符 $id:匹配 $file_count 个文件,开始拼接..." # 按文件名排序后拼接,保证输出顺序稳定 printf '%s\n' "${files[@]}" | sort | xargs cat > "./${id}_merged.txt" # 将所有参与拼接的原文件移至归档目录 printf '%s\n' "${files[@]}" | sort | while IFS= read -r f; do mv "$f" "$archive_dir/" done fi done
脚本适配的核心逻辑
- 标识符提取完全匹配规则:不管文件名后面有多少个下划线(比如
S111_1_R1.txt),都会准确取第一个下划线前的S111作为组标识,不会因为多下划线识别错误 - 自动判断文件数量:同组只有1个文件时,直接保留在主目录,不生成合并文件也不移动;同组有2个及以上文件时,才会执行拼接、移动原文件的操作,完全匹配你给的示例输出
- 兼容特殊路径:考虑到你的归档目录名带空格(
original files),脚本全程用双引号包裹路径,不会因为空格把单个文件拆成多个路径报错 - 避免重复处理:脚本运行时会自动跳过已经生成的
*_merged.txt文件,哪怕重复运行脚本也不会把之前的合并文件当成待处理的原始文件反复拼接 - 拼接顺序稳定:会按文件名自然排序后再拼接,避免同组文件拼接顺序混乱(比如不会把R2的内容放到R1前面)
注意:脚本基于Bash 4.0及以上版本编写,主流Linux发行版默认自带该版本;如果是macOS系统,可通过Homebrew安装新版Bash后使用,避免系统自带旧版Bash的语法不兼容问题。
之前尝试脚本的问题说明
你之前写的两段脚本无法正常运行的核心原因:
- 第一段脚本中
cut -zd_ -f1-参数错误:-f1-是提取从第一个分隔符到末尾的所有字段,本来需要的是第一个字段(也就是第一个下划线前的部分),应该是-f1才对,会导致提取的标识符完全错误;同时没有统计同组文件数量的逻辑,不管同组几个文件都强制生成分组文件,也没有移动原文件到归档目录的步骤- 第二段脚本硬编码了100-399的固定ID范围,完全不通用;同时存在Bash语法错误(变量赋值带空格、循环判断逻辑不通、命令末尾多余的
&符号),根本无法执行
新手使用步骤
- 把上面的脚本内容复制,粘贴到你存放待处理文件的目录下,存为
merge_files.sh - 打开终端,进入到这个目录,执行命令给脚本加执行权限:
chmod +x merge_files.sh - 运行脚本:
./merge_files.sh
运行完成后的目录结构完全符合你给出的示例:同组多文件会生成对应的{标识符}_merged.txt,参与拼接的原文件全部移到original files文件夹,单个文件直接留在主目录。
内容的提问来源于stack exchange,提问作者Mathilde
相关产品推荐
相关产品推荐

