【问题标题】:bash script to search through rows of data looking for match用于搜索数据行以查找匹配项的 bash 脚本
【发布时间】:2016-12-25 19:25:17
【问题描述】:

我有一个这样的输入文件。

dog
cat
bird
fish

我有一个这样的主文件。每行有不同数量的字段,但以三个为增量(所以 3,6,9,12,... 字段)

dog bird 123       asdf 456 cloud    sam 4444 barbara
bird sdf asdf
asdf 123 fdsa      cat asdff 1223sdf
aaaa fish ffff       ffff fish aaaa

我希望程序在输入列表中有匹配项时搜索输入文件并打印出整行。诀窍是我不想检查主文件中的所有列,只检查每个三元组的第一列 - 如下所示。

从输入列表中检查第 1 列、第 4 列或第 7 列是否匹配。

  • 所以单词 dog 匹配第一行的第 1 列 -
  • 所以单词 cat 匹配第三行的第 4 列 -
  • 所以单词 bird 匹配第二行的第 1 列 -
  • fish 一词与第 1、4 或 7 列不匹配 - 所以不算数

有意义吗?我找到了一种在 awk 中执行此操作的方法,但它涉及将数组作为参数发送,并且将数组解析出来相当棘手。

帮助?

【问题讨论】:

    标签: arrays bash awk


    【解决方案1】:

    试试:

    awk 'FNR==NR{a[$1];next} {for (i=1;i<=NF;i+=3) if ($i in a) {print;next}}'  input main
    

    例子:

    $ awk 'FNR==NR{a[$1];next} {for (i=1;i<=NF;i+=3) if ($i in a) {print;next}}'  input main
    dog bird 123       asdf 456 cloud    sam 4444 barbara
    bird sdf asdf
    asdf 123 fdsa      cat asdff 1223sdf 
    

    工作原理

    • FNR==NR{a[$1];next}

      如果我们正在读取第一个文件,即包含单词的文件,我们将单词作为关联数组a 中的键。然后,我们跳过其余的命令并跳转到 next 行重新开始。

    • for (i=1;i&lt;=NF;i+=3) if ($i in a) {print;next}

      对于每三个字段,我们检查它是否显示为关联数组a 中的键。如果是,那么我们打印该行并跳转到 next 行重新开始。

    【讨论】:

    • 我希望你没有得到回报。这太短了,近乎荒谬,但它确实有效。感谢并抱歉延迟回复您。
    【解决方案2】:

    我们可以使用新奇的associative array数据类型来存储搜索键,然后运行一个循环来对照关联数组检查主文件每一行的目标词,以测试该行是否匹配。

    INPUT_FILE='input.txt';
    MAIN_FILE='main.txt';
    
    ## first read in all words from the input file into an associative array
    ## assume one word per line
    declare -A keys=(); while read -r; do keys["$REPLY"]=1; done <"$INPUT_FILE";
    
    ## now read in one line at a time from the main file
    while read -r; do
        words=($REPLY); ## word splitting
        ## check for a match in multiple-of-3 words
        for ((i = 0; i < ${#words[@]}; i += 3)); do
            if [[ ${keys["${words[i]}"]} ]]; then
                echo "$REPLY"; ## echo the whole matching line
                break; ## don't need to check anymore
            fi;
        done;
    done <"$MAIN_FILE";
    

    输出:

    dog bird 123       asdf 456 cloud    sam 4444 barbara
    bird sdf asdf
    asdf 123 fdsa      cat asdff 1223sdf
    

    【讨论】:

      【解决方案3】:
      $ cat > trois.awk 
      BEGIN {                       # in the beginning
          RS="( +|\n)"              # set input record separator to spaces or newline
      } 
      NR==FNR {                     # for the first or input file only
          a[$1]                     # store the keywords
          next                      # avoid the rest of the code for the first file
      } 
      (($1 in a) && FNR%3==1) || i%3 {   # if a keyword matches in place 1, 4, 7, ...
          i++                            # or i counter allows printing (2,3, 5,6 ...)
          printf "%s%s", $1, i%3?OFS:ORS # print it pretty
      }
      $ awk -f trois.awk file1 file2
      dog bird 123
      bird sdf asdf
      cat asdff 1223sdf
      

      简而言之,RS 使 file2 成为一个单词列表,如果关键字与行号 mod 3 == 1 (1, 4, 7, ...) 匹配,则启动计数器 i 并打印接下来的两个词。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-12
        • 2018-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多