我在使用AWK搜索一个巨大的csv文件(可以称为file1(时遇到了一些困难。幸运的是,我有一个列表文件(可以称为file2(。我可以根据文件2中的索引列表文件来搜索我需要的行。然而,file1与任何其他普通文件不同,它类似于:
ID1, AC000112;AC000634;B0087;P01116;,ID1_name
ID2, AC000801;,ID2_name
ID3, P01723;F08734;,ID3_name
ID4, AC0014;AC0114;P01112;,ID4_name
...
IDn, AC0006;,IDn_name
IDm, Ac8007; P01167;,IDm_name
索引文件2类似:
AC000112
AC000801
P01112
P01167
所需的输出应该是:
ID1, AC000112;AC000634;B0087;P01116;,ID1_name
ID2, AC000801;,ID2_name
ID4, AC0014;AC0114;P01112;,ID4_name
IDm, Ac8007; P01167;,IDm_name
如果我使用
awk -F, 'NR==FNR{a[$1]; next} ($2 in a)' file2 file1
如果我加上"在文件2中每一行的末尾,我将只得到ID2, AC000801;,ID2_name
。如果我更改$2 ~ a[$1]
,它仍然不起作用。
因此,我想知道如何更改此命令以获得所需的结果。谢谢
您可以将字段分隔符设置为逗号,后跟可选空格[[:space:]]*,[[:space:]]*
然后,您可以用分号和可选空格[[:space:]]*;[[:space:]]*
分割文件1的第二个字段,并检查a
中是否存在其中一个字段
awk -F"[[:space:]]*,[[:space:]]*" 'NR==FNR{
a[$1]; next
}
{
split($2, parts, /[[:space:]]*;[[:space:]]*/)
for (i in parts) {
if (parts[i] in a) {
print $0; break;
}
}
}
' file2 file1
输出
ID1, AC000112;AC000634;B0087;P01116;,ID1_name
ID2, AC000801;,ID2_name
ID4, AC0014;AC0114;P01112;,ID4_name
IDm, Ac8007; P01167;,IDm_name
使用您显示的示例,请尝试以下awk
代码。
awk -F',|[[:space:]]+|;' '
FNR==NR{
for(i=2;i<=NF;i++){
arr[$i]=$0
}
next
}
($0 in arr){
print arr[$0]
}
' file1 file2
解释:添加对上述代码的详细解释。
awk -F',|[[:space:]]+|;' ' ##Setting field separator as comma, space(s), semi-colon here.
FNR==NR{ ##This condition will be TRUE when file1 is being read.
for(i=2;i<=NF;i++){ ##Using for loop to traverse from 2nd field to till last field.
arr[$i]=$0 ##Creating arr with index of current field, with value of current line.
}
next ##next will skip all further lines from here.
}
($0 in arr){ ##Checking condition if current line is present in arr.
print arr[$0] ##Printing arr with index of $0 here.
}
' file1 file2 ##Mentioning Input_file names here.
假设:
- 搜索字符串仅由字符和数字组成
GNU awk
的一个想法是,我们将单词边界标志附加到搜索模式中,然后执行正则表达式比较:
awk -F',' '
FNR==NR { regs["\<" $1 "\>"]; next }
{ for (regex in regs)
if ($2 ~ regex) { print; next }
}
' file2 file1
这将生成:
ID1, AC000112;AC000634;B0087;P01116;,ID1_name
ID2, AC000801;,ID2_name
ID4, AC0014;AC0114;P01112;,ID4_name
IDm, Ac8007; P01167;,IDm_name
如果你不局限于awk,我会使用grep来完成这个任务:
grep -Fwf file2 file1
-f file2
:使用file2
的每一行作为搜索字符串。-w
:只匹配整个单词(使得模式P01167
不匹配P011670
(。除字母、数字和下划线之外的任何字符都可以分隔单词(因此P01167;,
将匹配(。-F
:固定字符串-与字符串完全匹配,这样任何正则表达式字符都没有特殊含义。