【问题标题】:AWK searching records in one file for entries in another fileAWK 在一个文件中的记录中搜索另一个文件中的条目
【发布时间】:2019-06-23 20:42:51
【问题描述】:

我有一个 results.csv 文件,其中包含以下布局中的名称:

name1, 2(random number)  
name5, 3

还有一个sample.txt,其结构如下

record_seperator
name1
foo
bar
record_seperator
name2
bla
bluh

我想在 sample.txt 文件中搜索 results.csv 中的每个名称,如果找到,则将记录输出到文件中。 我试图从第一个文件中生成一个数组并搜索它,但我无法正确获取语法。 它需要在 bash 脚本中运行。如果有人有比 awk 更好的主意,那也很好,但我在它应该运行的机器上没有管理员权限。 真正的 csv 文件包含 10.000 个名称和 sample.txt 450 万条记录。 我是 awk 的血腥初学者,因此将不胜感激。 这是我目前的尝试,它不起作用,我不知道为什么:

#!/bin/bash
awk 'BEGIN{
while (getline < "results.csv")
{
split($0,name,",");
nameArr[k]=name[1];
}
{
RS="record_seperator"
FS="\n"
for (key in nameArr)
        {
         print nameArr[key]
         print $2
         if ($2==nameArr[key])
                 NR > 1
                 {
                #extract file by Record separator and name from line2
                print RS $0 > $2 ".txt"
                }
        }
}
}' sample.txt

编辑: 我的预期输出将是两个文件:

name1.txt

record_seperator
name1
foo
bar

name2.txt

record_seperator
name2
bla
bluh

【问题讨论】:

    标签: arrays awk full-text-search


    【解决方案1】:

    这是一个。 由于没有预期的输出,它只是输出原始记录

    $ awk '
    NR==FNR {              # process first file 
        a[$1]=RS $0        # hash the whole record with first field (name) as key 
        next               # process next record in the first file
    }                      # after this line second file processing
    $1 in a {              # if first field value (name) is found in hash a
        f=$1 ".txt"        # generate filename
        print a[$1] > f    # output the whole record
        close(f)           # preserving fds
    }' RS="record_seperator\n" sample RS="\n" FS="," results  # file order and related vars
    

    只有一场比赛:

    $ cat name1.txt
    record_seperator
    name1
    foo
    bar
    

    在 gawk 和 mawk 上测试,在 original-awk 上表现奇怪。

    【讨论】:

    • 感谢您的快速回答。我不得不承认,我并不完全理解它。我在原始帖子中添加了预期的输出。
    • 结果应包含 RS 行“record_seperator”
    • 非常感谢您的回答!抱歉这么晚才回来。我得了流感,然后堆积了大量工作。
    【解决方案2】:

    类似的东西,(未测试

    $ awk -F, 'NR==FNR {a[$1]; next}                  # fill array with names from first file
               $1 in a {print rt, $0 > ($1".txt")}    # print the record from second file
                       {rt = RT}' results.csv RS="define_it_here" sample.txt  
    

    由于您的记录分隔符在记录之前,您需要将其延迟一。

    使用内置的行/记录迭代器而不是解决它。

    【讨论】:

      【解决方案3】:

      你的代码错误:

      #!/bin/bash
      awk 'BEGIN{
      while (getline < "results.csv")
      {
      split($0,name,",");
      nameArr[k]=name[1];  ## <-- k not exists, you are rewriting nameArr[""] again and again.
      }
      {
      RS="record_seperator"
      FS="\n"
      for (key in nameArr) ## <-- only one key "" exists, it's never gonna equal to $2
              {
               print nameArr[key]  
               print $2
               if ($2==nameArr[key])
                       NR > 1
                       {
                      #extract file by Record separator and name from line2
                      print RS $0 > $2 ".txt"
                      }
              }
      }
      }' sample.txt
      

      还有您展示的示例:

      name1, 2(random number)  
      name5, 3  ## <-- name5 here, not name2 !
      

      name5 更改为name2,并更新了您自己的代码:

      #!/bin/bash
      awk 'BEGIN{
          while ( (getline line< "results.csv") > 0 ) {  # Avoid infinite loop when read erorr encountered.
              split(line,name,",");
              nameArr[name[1]]; # Actually no need do anything, just refer once to establish the key (name[1]).
          }
          RS="record_seperator";
          FS="\n";
      }
      
      $2 in nameArr {
              print RS $0;  #You can add `> $2 ".txt"` later yourself.
      }' sample.txt
      

      输出:

      record_seperator 
      name1            
      foo              
      bar              
      
      record_seperator 
      name2            
      bla              
      bluh             
      

      【讨论】:

        【解决方案4】:

        (在@Tiw 的带领下,我还在您的结果文件中将 name5 更改为 name2 以获得预期的输出)

        $ cat a.awk
        # collect the result names into an array
        NR == FNR {a[$1]; next}
        
        # skip the first (empty) sample record caused by initial record separator
        FNR ==  1 { next }
        
        # If found, output sample record into the appropriate file
        $1 in a {
            f =  ($1 ".txt")
            printf "record_seperator\n%s", $0  > f
        }
        

        使用 gawk 运行多字符 RS:

        $ gawk -f a.awk FS="," results.csv FS="\n" RS="record_seperator\n" sample.txt
        

        检查结果:

        $ cat name1.txt
        record_seperator
        name1
        foo
        bar
        $ cat name2.txt
        record_seperator
        name2
        bla
        bluh
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-05-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-10
          • 2013-12-03
          相关资源
          最近更新 更多