【问题标题】:Line after match of two files两个文件匹配后的行
【发布时间】:2013-07-10 22:56:36
【问题描述】:

我有类似last time 的问题。

这次我有一个header 文件,看起来像:

>random header 2
>random header name1

还有我的basefile

>random header name1
wonderfulstringwhatsoevergoeson
>random header 2
someotherline

现在的目标是获得以下输出:

另一条线

wonderfulstringwhatsoevergoeson

所以我想要来自basefile 的比赛后的行。 (只有这一个,不是标题)

重要的是,它应该保持header的顺序。

排序不起作用,因为它会保持字母顺序,这不应该发生。

我想不通,grep 如何比较两个文件并在匹配后给出行:/

【问题讨论】:

  • 您可以修改sort。只需使用类似sort _sort_function ... take a look here

标签: perl sed awk pattern-matching


【解决方案1】:

这将为您完成工作:

awk 'FNR==NR
    {
        a[$0]=FNR;i=FNR;next
    }
    ($0 in a)
    {
        t=$0;
        getline;b[a[t]]=$0
    }
    END
    {
        for(k=1;k<=i;k++)print b[k]
    }'  head base

【讨论】:

  • 这不会保持header的顺序!
  • BEGIN{i=0} 是多余的。
  • i 是多余的,只需在 END 中循环到 NR-FNR。如果您正在考虑使用getline,请确保您阅读了awk.info/?tip/getline 并完全理解它并且可以接受所有警告。然后不要那样使用它。不过,我确实喜欢这个主意,为此 +1。
  • 记得把你的左大括号和条件放在同一行 - 正如所写的那样,每个动作块都将针对每一行执行,而不仅仅是那些匹配条件的。
【解决方案2】:

应该这样做:

awk '
   { recs[NR] = $0 }  # store the header lines in 1->(NR-FNR) and the basefile lines in ((NR-FNR)+1)->NR
   END {
       for (hdrNr=1; hdrNr<=(NR-FNR); hdrNr++) {
           hdr = recs[hdrNr]
           for (lineNr=(NR-FNR)+1; lineNr<=NR; lineNr++) {
               line = recs[lineNr]
               if (line == hdr) {
                   print recs[lineNr+1]
               }
           }
       }
   }
' header basefile

遵循@Vijays 的想法,即仅将匹配行存储在一个数组中,该数组按读取标题的顺序进行索引,以下是在没有 getline、没有不必要的变量、使用有意义的变量名和不打印的情况下如何做到这一点每个不匹配的标题的空行:

awk '
    NR==FNR { hdr2nr[$0] = FNR; next }
    hdrNr   { hdrNr2line[hdrNr] = $0 }
    { hdrNr = hdr2nr[$0] }
    END {
        for(hdrNr=1; hdrNr<=(NR-FNR); hdrNr++)
            if (hdrNr in hdrNr2line)
                print hdrNr2line[hdrNr]
    }
'  header basefile

假设给定的标头只能在基本文件中出现一次。

【讨论】:

    【解决方案3】:

    basefile 读入%h 哈希,然后遵循header 文件中指定的密钥顺序,

    perl -ne 'BEGIN{ open $F,pop or die $!; %h=<$F> } print $h{$_}' header basefile
    

    【讨论】:

    • @EdMorton 这个看起来还不错:)
    【解决方案4】:

    试试这个 bash 单行:

    while read line; do match=$(sed -n "/$line/{ n;p}" basefile); echo $match; done < 'header'
    

    当你的基本文件总是有对应标题的一行定义时,这将起作用。

    标题:

    sat:~# cat header
    >random header 2
    >random header name1
    

    基础文件:

     sat:~# cat basefile 
     >random header name1 
     wonderfulstringwhatsoevergoeson
     >random header 2 
     someotherline
    

    输出:

     sat:~# while read line; do match=$(sed -n "/$line/{ n;p}" basefile);echo $match; done < 'header' 
     someotherline
     wonderfulstringwhatsoevergoeson
    

    【讨论】:

      【解决方案5】:

      这可能对你有用(GNU sed):

      sed -r 'N;s/^(.*)\n(.*)/s|^\1$|\2|/' base_file | sed -f - header_file
      

      base_file 转换为sed 脚本并针对header_file 运行它。

      【讨论】:

        猜你喜欢
        • 2017-07-07
        • 2018-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-25
        • 1970-01-01
        • 2015-04-08
        • 1970-01-01
        相关资源
        最近更新 更多