【问题标题】:How to use grep or awk to process a specific column ( with keywords from text file )如何使用 grep 或 awk 处理特定列(使用文本文件中的关键字)
【发布时间】:2014-08-08 01:11:25
【问题描述】:

我尝试了多种 grep 和 awk 命令的组合来处理文件中的文本。

这是此类客户的列表:

John,Mills,81,Crescent,New York,NY,john@mills.com,19/02/1954

我试图将这些记录分为两类,男性和女性。

我有一个大约 5000 个女性名字的列表,全部都是纯文本,都在一个文件中。

如何“grep”第一列(因为我只匹配名字)但仍打印整个客户记录?

我发现“剪切”第一列和grep --file=female.names.txt 很容易,但这样就不会再打印整条记录了。

我知道 awk 选项,但在这种情况下,我不知道如何从文件中读取女性姓名。

awk -F ',' ' { if($1==" ???Filename??? ") print $0} '

非常感谢!

【问题讨论】:

  • 嗯......我不会用右手打赌你的名单的准确性。为什么?因为 Andrea 在盎格鲁撒克逊语国家是一个“女性”名字,但在例如意大利。还有像香农这样的案例,两者都可以。只是说。
  • 女性的反义词是男性,而不是男性。这是没有意义的,因为仅适用于男性或女性的英文名字就有很多(Leslie、Jackie、Hunter、Skylar、Billy、Erin、Reece 等等……)——我无法想象5000 个“女性名字”列表,其中没有一些名字会让一些男人坐起来说“嘿!”。
  • 你们俩都是对的。我对“美国”名字进行了一些频率分析,然后转到了欧洲。 5000 个名字是美国、欧洲和一些中东的汇编。我还没有来自非洲的任何东西。你们的 cmets 会让我现在必须工作更多 :)

标签: linux bash awk


【解决方案1】:

你可以用 awk 做到这一点:

awk -F, 'NR==FNR{a[$0]; next} ($1 in a)' female.names.txt file.csv 

将打印 csv 文件的行,其中包含在您的文件 female.names.txt 中找到的任何人的名字。

awk -F, 'NR==FNR{a[$0]; next} !($1 in a)' female.names.txt file.csv 

将输出在female.names.txt 中找不到的行。

这假设您的 female.names.txt 文件的格式类似于:

Heather
Irene
Jane

【讨论】:

  • 嘿约翰,我不确定我做错了什么,但是一旦我向下移动列,awk 不再匹配名称。我试过: awk -F, 'NR==FNR{a[$3]; next} ($1 in a)' ,因此将列位置更改为 3。请问这到底是如何工作的?
  • 您在哪个文件中更改列,csv 文件或名称列表?如果要匹配 csv 文件中的第 3 列,只需将 $1 in a 更改为 $3 in a
【解决方案2】:

试试这个:

grep --file=<(sed 's/.*/^&,/' female.names.txt) datafile.csv

这会将女性姓名列表中的所有姓名更改为正则表达式^name,,因此它仅匹配行首并后跟逗号。然后它使用进程替换将其用作与数据文件匹配的文件。

【讨论】:

    【解决方案3】:

    另一种选择是 Perl,如果您不是非常熟悉 awk,它会很有用。

    #!/usr/bin/perl -anF,
    use strict;
    our %names;
    
    BEGIN {
        while (<ARGV>) {
            chomp;
            $names{$_} = 1;
        }
    }
    
    print if $names{$F[0]};
    

    运行(假设您将此文件命名为filter.pl):

    perl filter.pl female.names.txt < records.txt
    

    【讨论】:

    • 非常感谢你们提供有用的反馈!这两种方法我都试过了,都有效!叹息:) 克里斯的方法只是另一个问题。我将如何更改列和分隔符?比如说我有 shoescategory;John;Mills;addres; ; ; ; ; ;我需要用';'解析第二列作为分隔符。再次感谢!!
    • @user3920489 将第一行的,改为;,并使用$F[1]而不是$F[0]访问第二列。
    • perl 解决方案在哪些方面比 awk 解决方案更好? perl 解决方案似乎更长,更难阅读,并且不像 awk 解决方案那样可移植 - 我错过了什么?
    • @EdMorton Perl 版本使用哈希表,为每一行提供摊销常数时间查找。根据我对 John 的 awk 解决方案的了解,它使用数组,因此 $1 in a 检查对于每行的名称列表的长度是线性的。如果名称列表很长并且数据有很多行,这将产生灾难性的性能。
    • 在 perl 中发布答案很好,不需要删除它,我只是想知道 perl 比 awk 更好的陈述背后的基本原理,因为 AFAIK awk 在各个重要方面都比 perl 好用于操作文本文件。也许只是编辑您的答案以删除该声明?
    【解决方案4】:

    所以,我想出了以下几点:

    假设,您有一个文件,在名为 test.txt 的文件中包含以下行:

    abe 123 bdb 532

    xyz 593 iau 591

    现在您要查找包含第一个字段的行,其中第一个和最后一个字母作为元音。如果你做了一个简单的grep,你会得到这两行,但下面只会给你第一行,这是所需的输出:

    egrep "^([0-z]{1,} ){0}[aeiou][0-z]+[aeiou]" test.txt
    

    然后你想找到包含第三个字段的行,其中第一个和最后一个字母作为元音。同样,如果你做了一个简单的grep,你会得到这两行,但下面只会给你第二行,它是所需的输出:

    egrep "^([0-z]{1,} ){2}[aeiou][0-z]+[aeiou]" test.txt
    

    第一个花括号{1,} 中的值指定前面的字符(根据ASCII 表从0 到z 的范围)可以出现任意次数。之后,我们有字段分隔符space in this case。将第二个花括号 {0} or {2} 中的值更改为 desired field number-1。然后,使用正则表达式来提及您的条件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-25
      • 1970-01-01
      • 2015-10-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多