【问题标题】:Obtain patterns from a file, compare to a column of another file, print matching lines, using awk从文件中获取模式,与另一个文件的列进行比较,打印匹配行,使用 awk
【发布时间】:2013-01-06 09:51:31
【问题描述】:

我基本上想结合

grep -f 

awk '{ if($2=="this is where I'd like to input a file of fixed string patterns") print $0}'

也就是说,我想使用模式输入文件(文件 2)搜索文件(文件 1)的特定列。如果简单地找到匹配项:

> outputfile.txt

从之前的帖子来看,这条 awk 行非常接近:

awk 'NR==FNR{a[$0]=1;next} {n=0;for(i in a){if($0~i){n=1}}} n' file1 file2

取自Obtain patterns in one file from another using ack or awk or better way than grep?

但它不会搜索文件 1 的特定列。我也对其他工具持开放态度。

【问题讨论】:

    标签: unix sed awk grep


    【解决方案1】:

    你找到的例子确实和你想要的很接近,唯一的区别是你不想匹配整行($0)。

    修改成这样:

    awk 'NR==FNR { pats[$0]=1; next } { for(p in pats) if($2 ~ p) { print $0; break } }' patterns file
    

    如果您只需要固定字符串匹配,请改用index() 函数,即将$2 ~ p 替换为index($2, p)

    您还可以将列号作为参数提供给 awk,例如:

    awk -v col=$col 'NR==FNR { pats[$0]=1; next } { for(p in pats) if($col ~ p) { print $0; break } }' patterns file
    

    编辑 - 整个字段匹配

    您可以使用== 运算符完成此操作:

    awk -v col=$col 'NR==FNR { pats[$0]=1; next } { for(p in pats) if($col == p) { print $0; break } }' patterns file
    

    【讨论】:

    • 谢谢!这适用于较少数量的模式。我的模式是固定的字符串,我只想要完全匹配。我知道,例如在使用 Grep 时,添加固定字符串选项确实可以减少处理时间。有 awk 等价物吗?
    • @ChrisJ.Vargo:是的,index 函数会进行固定字符串匹配(如答案中所述)。
    • 谢谢,但是:awk 'NR==FNR { pats[$0]=1;下一个 } { for(p in pats) if(index($5, p)) { print $0; break } }' 1.txt PrimaryTweets.tsv > 1Method2index.tsv 不返回完全匹配。有没有办法强制完全匹配?
    • @ChrisJ.Vargo:那么您真正想要的是全词匹配还是全字段匹配?查看整个字段匹配的编辑。如果您的意思是整个单词,则需要使用正则表达式或进行进一步的字段拆分。
    【解决方案2】:

    这是使用awk:

    awk 'BEGIN { while(getline l < "patterns.txt") PATS[l] } $2 in PATS' file2
    

    file1 是您正在搜索的文件,patterns.txt 是每个文件具有一个精确模式的文件。隐含的{print} 已被省略,但您可以添加它并在那里做任何您喜欢的事情。

    条件$2 in PATS 为真,即第二列恰好是模式之一。

    如果patterns.txt被视为正则匹配,修改为

    ok=0;{for (p in PATS) if ($2 ~ p) ok=1}; ok
    

    例如,针对patterns.txt 中的所有正则表达式测试$2,并打印 第三列,如果第二列匹配:

    awk 'BEGIN { while(getline l < "patterns.txt") PATS[l] } 
         ok=0;{for (p in PATS) if ($2 ~ p) ok=1}; ok 
        {print $3}' < file2
    

    这是perl 中的一个版本。类似于awk 版本,只是它 使用正则表达式而不是字段。

    perl -ne 'BEGIN{open $pf, "<patterns.txt"; %P=map{chomp;$_=>1}<$pf>} 
       /^\s*([^\s]+)\s+([^\s]+).*$/ and exists $P{$2} and print' < file2
    

    分开:

    BEGIN{
      open $pf, "<patterns.txt"; 
      %P = map {chomp;$_=>1} <$pf>;
    }
    

    将您的模式文件读入 has %P 以便快速查找。

    /^\s*([^\s]+)\s+([^\s]+).*$/ and  # extract your fields into $1, $2, etc
    exists $P{$2} and                 # See if your field is in the patterns hash
    print;                            # just print the line (you could also 
                                      # print anything else; print "$1\n"; etc)
    

    如果您的输入文件是制表符分隔的(并且当您知道 字段之间只有一个标签)。这是一个匹配模式的示例 针对第 5 列:

     perl -F"\t" -ane '
        BEGIN{open $pf, "<patterns.txt"; %P=map{chomp;$_=>1}<$pf>} 
        exists $P{$F[4]} and print ' file2
    

    这要归功于 perl 的 -F 运算符,它告诉 perl 自动拆分为列 基于分隔符(在这种情况下为\t)。 请注意,由于perl 中的数组从0 开始,所以$F[4] 是第5 个字段。

    【讨论】:

    • 令人印象深刻。似乎我不能再避免与awk 打交道。谢谢你的详细解释。
    • 谢谢!这适用于较少数量的模式。在我的 1,000 个大列表中,它似乎内存不足。我的模式是固定的字符串,我只想要完全匹配。我知道,例如在使用 Grep 时,添加固定字符串选项 (-F) 确实可以减少处理时间。有 awk 等价物吗?
    • 如果你试试我刚刚发布的perl 版本呢?
    • 你运行的是什么版本的awk 和什么类型的OS
    • 当输入一个大列表时,perl 版本似乎只检索一个模式,然后退出。奔跑的山狮。
    【解决方案3】:

    我不太确定在这种情况下,列的区别在哪一部分起作用。您是否处理某种 csv 文件?您是否处理正则表达式列表文件中的列分隔符?如果文件中没有由某些分隔符分隔的不同列,则可以使用grep

    grep -o -f file2 file1
    

    如果列是一个问题,可能是这样的:

    grep -o "[^,]*" file1 | grep -f file2
    

    , 是分隔符。

    【讨论】:

    • 制表符分隔,第五列。 grep 是否可以跳过前 55 个字符,然后仅在第一个选项卡之前找到匹配项时才返回匹配项?这将迫使它从第 5 列开始,并在下一列之前停止。我喜欢 grep,因为使用固定字符串选项,它比 awk 快得多。
    • grep 中有一个关于选项卡的错误,但是通过使用 Perl 开关 -P,您可以像预期的那样传递它们:\t。但是,在这里使用cut 似乎更合适,其分隔符默认为制表符,可以准备您的file1 (-f 5)。
    猜你喜欢
    • 2016-07-30
    • 1970-01-01
    • 2019-03-28
    • 2018-08-22
    • 1970-01-01
    • 2015-09-16
    • 1970-01-01
    • 2020-08-20
    • 2012-09-25
    相关资源
    最近更新 更多