使用awk删除第10列含"present"的行遇异常,求原因及更佳方案
为啥会出现这种奇怪的情况?
大概率是你的数据行里有带空白字符的字段——就是你提到的那两行,它们的第3列本身包含空格(比如类似"xyz present abc"这种值),导致awk默认按空白分割字段时,字段的编号和你预想的完全对不上。
举个实际的例子:假设某行的第3列是"hello present world",awk会把这个拆成3个独立字段(hello、present、world),那原本的第10列就被挤到了更靠后的位置(比如变成第12列)。这时候你用$10!="present"判断,自然不会命中该行真实的第10列,本该被删掉的行就留了下来。
还有一种小概率情况:那两行的第10列值带了额外的空格(比如" present"或者"present "),或者被引号包裹着(比如"\"present\""),和你写的"present"完全不匹配,所以awk的条件没触发。
靠谱的解决办法
根据你的数据格式,分两种场景来处理:
场景1:数据用固定分隔符(制表符/逗号)分隔
如果你的data.anno是制表符分隔的(注释文件常用这种格式),直接指定awk的字段分隔符为制表符就行:
BEGIN {FS="\t"} $10!="present" {print} data.anno > data_output.anno
要是是逗号分隔的CSV格式,就把FS改成逗号:
BEGIN {FS=","} $10!="present" {print} data.anno > data_output.anno
指定准确的分隔符能让awk精准识别每一列,再也不会因为字段带空格导致编号错位。
场景2:字段带空白且有引号包裹(比如标准CSV)
如果你的字段是用双引号包裹的(比如"abc present", "def", ...),普通的分隔符设置搞不定,这时候可以用专门处理CSV的工具,比如csvkit里的csvfilter:
csvfilter -c 10 -ne 'present' data.anno > data_output.anno
或者用GNU awk的FPAT功能来定义字段的匹配规则(适配逗号分隔+带引号字段的情况,可根据你的实际分隔符调整):
BEGIN {FPAT="([^,]+)|(\"[^\"]+\")"} $10!="present" {print} data.anno > data_output.anno
先验证再修改的小技巧
处理前你可以先确认那两行的字段编号是否正确,比如用awk打印出那两行的第10列看看:
# 假设那两行的行号是123和456,替换成实际行号就行 sed -n '123p;456p' data.anno | awk '{print $10}'
如果输出的不是present,那就坐实了字段分割的问题,赶紧调整FS或者FPAT就行。
另外提个小建议:用>代替>>来重定向输出,避免多次执行命令时把内容重复追加到目标文件里。
内容的提问来源于stack exchange,提问作者Nuthatch92

