从特定索引处的另一个文件中删除包含字符串的行

时间:2019-06-04 16:49:18

标签: unix awk sed grep

我有一个名为main_file的文件,其列数可变。 main_file的前两列始终具有相同的字符数和相同的字段分隔符,并且稍后提供各种信息。该行其余部分中的信息可以是任何信息,包括与第一列相同的信息,因此我不能仅grep该字符串。这些行也不一定是唯一的。

 aaaa  A --------- fdsfadf 
 aaaa  B --------- fasdfa
 bbbb  A --------- hgfhf
 bbbb  B --------- hftret jhtruyr
 1ulm  A --------- tret aaaa  A
 1ulm  X --------- fsdfs fdsfs
 1ulm  B --------- yttertre   ertre
 cccc  A --------- sdfsa      mjhhfdgdf
 cccc  B --------- werwfds     fsa wrew
 cccc  P --------- fsda   wrewr
 ghh1  A --------- rwerw     wrew
 ghh1  G --------- werwe    bbbb  B
 ghh2  A --------- Pewrew   trerew rwew
 ghh2  G --------- fdss         rewrw8
 ghh4  A --------- qweqe          321313
 ghh4  G --------- 3242   wrewrw
 aaaa  B --------- fasdfa erwrew

我有一个名为code_list的文件,其中包含所有需要从文件中删除的条目。

aaaa  A
aaaa  B
bbbb  A
bbbb  B
cccc  A
cccc  B
cccc  P

我想从main_file中删除或注释掉code_list中有条目的所有行

所以我想得到(以相同的顺序):

* aaaa  A --------- fdsfadf 
* aaaa  B --------- fasdfa
* bbbb  A --------- hgfhf
* bbbb  B --------- hftret jhtruyr
 1ulm  A --------- tret aaaa  A
 1ulm  X --------- fsdfs fdsfs
 1ulm  B --------- yttertre   ertre
* cccc  A --------- sdfsa      mjhhfdgdf
* cccc  B --------- werwfds     fsa wrew
* cccc  P --------- fsda   wrewr
 ghh1  A --------- rwerw     wrew
 ghh1  G --------- werwe    bbbb  B
 ghh2  A --------- Pewrew   trerew rwew
 ghh2  G --------- fdss         rewrw8
 ghh4  A --------- qweqe          321313
 ghh4  G --------- 3242   wrewrw
* aaaa  B --------- fasdfa erwrew

或获取:

 1ulm  A --------- tret utrtry
 1ulm  X --------- fsdfs fdsfs
 1ulm  B --------- yttertre   ertre
 ghh1  A --------- rwerw     wrew
 ghh1  G --------- werwe    lkjl
 ghh2  A --------- Pewrew   trerew rwew
 ghh2  G --------- fdss         rewrw8
 ghh4  A --------- qweqe          321313
 ghh4  G --------- 3242   wrewrw

我尝试运行myscript.sh代码列表

其中myscript.sh是:

#!/bin/bash

while IFS='' read -r line || [[ -n "$line" ]]; do


    awk '{if(substr($0,2,7) == "'$line'") {print "*"$0}else{print $0}}' main_file > out


done < "$1"

但出现错误“未终止的字符串” 当我尝试

awk '{if(substr($0,2,7) == "aaaa  A") {print "*"$0}else{print $0}}' main_file > out

然后它起作用。但是文件code_list太长了,无法手动编写每个名称,而且我无法以任何方式将其设置为变量。

删除或注释掉这些行的最佳方法是什么?

4 个答案:

答案 0 :(得分:2)

在这里,您可以使用NR == FNR技术来让awk处理两个文件。当NR == FNR时,表示正在处理的记录号与当前文件中的记录号相同,换句话说,您正在处理参数列表中的第一个文件(在这种情况下,code_list

第一个文件的关联操作是为我们在处理第二个文件(main_file)时建立查找表。

由于第一个操作中的next语句使awk立即转到下一条记录而无需执行任何其他操作,因此当我们执行第二步时,我们知道我们正在处理第二个文件。第二步仅具有以下条件:前两个字段不在查找表中。在这种情况下,它会执行默认操作,即打印该行。

 $ awk 'NR == FNR {a[$1 FS $2]; next} !(($1 FS $2) in a)' code_list main_file 
 1ulm  A --------- tret aaaa  A
 1ulm  X --------- fsdfs fdsfs
 1ulm  B --------- yttertre   ertre
 ghh1  A --------- rwerw     wrew
 ghh1  G --------- werwe    bbbb  B
 ghh2  A --------- Pewrew   trerew rwew
 ghh2  G --------- fdss         rewrw8
 ghh4  A --------- qweqe          321313
 ghh4  G --------- 3242   wrewrw

答案 1 :(得分:2)

我的其中一项工作:

awk 'NR==FNR {a[$0]++;next} {b=substr($0,2,7)} !(b in a)' filter data
awk 'NR==FNR {a[$0]++;next} !(($1"  "$2) in a)' filter data
 1ulm  A --------- tret aaaa  A
 1ulm  X --------- fsdfs fdsfs
 1ulm  B --------- yttertre   ertre
 ghh1  A --------- rwerw     wrew
 ghh1  G --------- werwe    bbbb  B
 ghh2  A --------- Pewrew   trerew rwew
 ghh2  G --------- fdss         rewrw8
 ghh4  A --------- qweqe          321313
 ghh4  G --------- 3242   wrewrw

答案 2 :(得分:2)

$ awk '{k=$1 FS $2} NR==FNR{a[k]; next} !(k in a)' code_list main_file
 1ulm  A --------- tret aaaa  A
 1ulm  X --------- fsdfs fdsfs
 1ulm  B --------- yttertre   ertre
 ghh1  A --------- rwerw     wrew
 ghh1  G --------- werwe    bbbb  B
 ghh2  A --------- Pewrew   trerew rwew
 ghh2  G --------- fdss         rewrw8
 ghh4  A --------- qweqe          321313
 ghh4  G --------- 3242   wrewrw

$ awk '{k=$1 FS $2} NR==FNR{a[k]; next} {print (k in a ? "*" : "") $0}' code_list main_file
* aaaa  A --------- fdsfadf
* aaaa  B --------- fasdfa
* bbbb  A --------- hgfhf
* bbbb  B --------- hftret jhtruyr
 1ulm  A --------- tret aaaa  A
 1ulm  X --------- fsdfs fdsfs
 1ulm  B --------- yttertre   ertre
* cccc  A --------- sdfsa      mjhhfdgdf
* cccc  B --------- werwfds     fsa wrew
* cccc  P --------- fsda   wrewr
 ghh1  A --------- rwerw     wrew
 ghh1  G --------- werwe    bbbb  B
 ghh2  A --------- Pewrew   trerew rwew
 ghh2  G --------- fdss         rewrw8
 ghh4  A --------- qweqe          321313
 ghh4  G --------- 3242   wrewrw
* aaaa  B --------- fasdfa erwrew

答案 3 :(得分:1)

我建议将文件code_list中的数据转换为grep的模式,并固定到行的开头

sed 's/^/^/' code_list > code_list2

编辑:如果code_listmain_file都包含相同的前导空格,则此方法将起作用。

假设文件code_list仅包含一个前导空格,则结果文件code_list2将包含

^ aaaa  A
^ aaaa  B
^ bbbb  A
^ bbbb  B
^ cccc  A
^ cccc  B
^ cccc  P

如果前导空格可能不同(或不存在),则可以扩展替换:

sed 's/^ */^ */' code_list > code_list2

这将删除任意数量的前导空格,并为任意数量的前导空格添加一个模式。处理标签也需要进行其他更改。

生成的文件code_list2将包含

^ *aaaa  A
^ *aaaa  B
^ *bbbb  A
^ *bbbb  B
^ *cccc  A
^ *cccc  B
^ *cccc  P

(编辑结束)

然后使用它来提取不匹配的行

grep -v -f code_list2 main_file

有了这个我

 1ulm  A --------- tret aaaa  A
 1ulm  X --------- fsdfs fdsfs
 1ulm  B --------- yttertre   ertre
 ghh1  A --------- rwerw     wrew
 ghh1  G --------- werwe    bbbb  B
 ghh2  A --------- Pewrew   trerew rwew
 ghh2  G --------- fdss         rewrw8
 ghh4  A --------- qweqe          321313
 ghh4  G --------- 3242   wrewrw

如果您使用支持<( command )的shell,例如bash,您可以将两个命令组合为

grep -v -f <(sed 's/^/^/' code_list) main_file

编辑:或处理不同的前导空格

grep -v -f <(sed 's/^ */^ */' code_list) main_file