使用Sed批量修改多TSV文件第二列内容并覆盖原文件
批量修改TSV文件第二列并保存回原文件的解决方案
我懂你遇到的问题了——直接用重定向>保存修改内容时,shell会先清空原文件,导致awk根本读不到数据,自然没法完成修改。下面给你两种可靠的解决办法:
方法一:awk + 临时文件(通用且安全)
这是最稳妥的方案,用临时文件中转处理后的内容,再替换原文件:
# 遍历当前目录下所有.tsv文件 for file in *.tsv; do # 处理内容:表头直接输出,其他行给第二列加前缀 awk 'NR==1{print; next} {$2="X1_"$2; print}' "$file" > "$file.tmp" # 用临时文件覆盖原文件 mv "$file.tmp" "$file" done
代码解释:
NR==1{print; next}:识别第一行(表头),直接打印后跳过后续逻辑,保证表头不变{$2="X1_"$2; print}:从第二行开始,给第二列拼接X1_前缀,然后输出整行- 先输出到临时文件再替换,避免了直接重定向清空原文件的坑
如果你的TSV是严格用制表符分隔的(不是空格),可以指定分隔符来保证格式不混乱:
for file in *.tsv; do awk -F '\t' -v OFS='\t' 'NR==1{print; next} {$2="X1_"$2; print}' "$file" > "$file.tmp" mv "$file.tmp" "$file" done
这里-F '\t'指定输入分隔符为制表符,OFS='\t'指定输出分隔符为制表符,确保处理后还是标准TSV格式。
方法二:用sponge工具(更简洁)
如果你的系统安装了moreutils工具包(Ubuntu/Debian可以用sudo apt install moreutils安装),可以用sponge工具直接把处理结果写回原文件,省去临时文件的步骤:
for file in *.tsv; do awk 'NR==1{print; next} {$2="X1_"$2; print}' "$file" | sponge "$file" done
sponge的作用是先把所有输入内容读入内存,再写入目标文件,不会提前清空原文件,完美解决了直接重定向的问题。
重要提醒
操作前一定要备份文件! 比如先把所有TSV文件复制到备份目录:
mkdir -p tsv_backup cp *.tsv tsv_backup/
避免误操作导致数据丢失,毕竟数据安全永远是第一位的~
内容的提问来源于stack exchange,提问作者Natha




