如何使用Bash从制表符分隔文件中移除另一文件的指定值?
使用Bash实现从制表符分隔文件中移除指定元素
当然可行!这里有两种实用的Bash方案帮你搞定这个需求,都是日常处理文本时常用的技巧:
方法一:使用awk(推荐,高效且灵活)
awk特别适合处理这种字段级别的文本操作,直接一步到位:
awk 'BEGIN {FS=OFS="\t"} NR==FNR {exclude[$1]; next} {for (i=1; i<=NF; i++) if (!($i in exclude)) printf "%s%s", $i, (i==NF?ORS:OFS)}' 文件B 文件A > 文件C
命令解释:
BEGIN {FS=OFS="\t"}:一开始就设置输入和输出的分隔符为制表符,保证处理前后格式一致。NR==FNR {exclude[$1]; next}:先处理文件B,把每个要移除的元素存入exclude数组,存完就跳过后续逻辑,专注处理下一个文件。- 处理文件A时,遍历每一个字段,只要字段不在
exclude数组里就输出,最后自动处理字段间的制表符和末尾的换行。
方法二:使用grep+tr组合(适合简单场景)
如果觉得awk有点复杂,也可以用grep和tr的组合来实现:
# 先把文件B的元素转换成正则匹配模式(适用于文件B每行一个元素的情况) pattern=$(tr '\n' '|' < 文件B | sed 's/|$//') # 拆分文件A的元素、过滤、再重组 echo "$(cat 文件A)" | tr '\t' '\n' | grep -vE "^($pattern)$" | tr '\n' '\t' | sed 's/\t$//' > 文件C
命令解释:
- 第一步把文件B的每行元素转成
A|D|J|M|U|V这种正则模式,方便grep精准匹配。 - 把文件A的制表符换成换行,让每个元素单独占一行,方便过滤。
- 用
grep -v过滤掉匹配模式的行(也就是要移除的元素)。 - 再把换行换回制表符,最后用sed去掉末尾多余的制表符,得到干净的结果。
小提示:如果文件B里的元素是一行空格分隔的,先执行
cat 文件B | tr ' ' '\n' > 文件B.tmp,再用文件B.tmp代替上面命令里的文件B即可。
内容的提问来源于stack exchange,提问作者Lorenzo




