【问题标题】:Print only first and last matching patterns仅打印第一个和最后一个匹配模式
【发布时间】:2015-08-05 17:29:47
【问题描述】:

我是脚本新手,正在学习中,感谢您提供的所有帮助。我有一个包含以下数据的文件:

0252    Fri 03 Jul 2015      84082679  
0252    Fri 10 Jul 2015      81473945  
0252    Fri 17 Jul 2015      87405062  
0252    Fri 24 Jul 2015      89400396  
0253    Fri 03 Jul 2015      29038894  
0253    Fri 10 Jul 2015      29392107  
0253    Fri 17 Jul 2015      31271055  
0253    Fri 24 Jul 2015      31367348  
071    Fri 03 Jul 2015      18594024  
071    Fri 10 Jul 2015      18568430  
071    Fri 17 Jul 2015      18648903  
071    Fri 24 Jul 2015      18887643  
072    Fri 03 Jul 2015      20141235  
072    Fri 10 Jul 2015      19563727  
072    Fri 17 Jul 2015      19573266

我想要的输出如下所示:

0252    Fri 03 Jul 2015      84082679  
0252    Fri 24 Jul 2015      89400396  
0253    Fri 03 Jul 2015      29038894  
0253    Fri 24 Jul 2015      31367348  
071    Fri 03 Jul 2015      18594024  
071    Fri 24 Jul 2015      18887643  
072    Fri 03 Jul 2015      20141235  
072    Fri 17 Jul 2015      19573266  

输入数据的第一列定义了“组”。我想从每个组中准确打印两行:第一行和最后一行。

我想使用 awk 来获得我想要的结果,因为我正在尝试将此信息排序为最终输出。非常感谢任何帮助,谢谢。

【问题讨论】:

  • 你的输入和输出到底有什么区别?我错过了一些明显的东西吗? IE。你想让你的代码做什么?
  • @MaximillianLaumeister,我刚刚编辑了这个问题,添加了一个可以澄清问题的句子。 “输入数据中的第一列定义了“组”。从每个组中,我想打印两行:第一行和最后一行。”

标签: linux bash awk


【解决方案1】:

Perl 来救援!

perl -lane '
            if ($F[0] eq $id) {
                $keep = $_
            } else {
                $id = $F[0];
                print $keep if defined $keep;
                print
            }
            }{ print $keep
            ' < input.txt > output.txt
  • -n逐行读取输入
  • -a 将每一行拆分为 @F 数组
  • -l 将换行符添加到 print
  • $id 用于保留第一列的值
  • $keep 记得最后一行。当$id 发生变化时,会打印$keep 和当前行。
  • 在 Eskimo 问候运算符 }{ 之后,在处理完整个文件后打印最后一行。

【讨论】:

  • 所以,为了澄清问题:第 1 列“分组”数据。从每组中,我们正好打印两行。具体来说,第一行和最后一行。 但请注意,在示例数据中,每个组在内部按日期排序 - 您理解此排序无关紧要。这个对吗?也许您可以编辑您的答案以澄清您要回答的问题?
  • @AaronMcDaid:它打印第一列中每个 ID 的第一行和最后一行。它所做的唯一假设是每个“块”必须是连续的。这个问题没有提到日期。
【解决方案2】:
$ awk -v h=99 'h>$3{if (last) print last;print;} {h=$3;last=$0;} END{print last}' file
0252    Fri 03 Jul 2015      84082679  
0252    Fri 24 Jul 2015      89400396  
0253    Fri 03 Jul 2015      29038894  
0253    Fri 24 Jul 2015      31367348  
071    Fri 03 Jul 2015      18594024  
071    Fri 24 Jul 2015      18887643  
072    Fri 03 Jul 2015      20141235  
072    Fri 17 Jul 2015      19573266

工作原理

脚本使用两个变量:hlasth 是上一行第三个字段的值,last 是最后一行的文本。 h 的任何减少都会触发打印。

  • -v h=99

    h的初始值设置为一个较大的数字。

  • h&gt;$3{if (last) print last;print;}

    如果h 大于字段 3,则打印上一行(如果有的话)和当前行。

  • h=$3;last=$0;

    更新hlast

  • END{print last}

    打印最后一行。

【讨论】:

    【解决方案3】:

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

    sed -r '1p;N;/^(\S+\s+).*\n\1/D;2s/.*\n//' file
    

    总是打印第一行。将下一行附加到当前行,并将第一个字段的第一个字段与第二个字段的第一个字段进行比较。如果它们相同,请删除第一个并重复。否则,打印两行,但如果在第 2 行,则只打印第二行。

    【讨论】:

      【解决方案4】:
      $ cat tst.awk
      $1 != p1 { print p0 $0 }
      { p1 = $1; p0 = $0 ORS }
      END { printf "%s", p0 }
      
      $ awk -f tst.awk file
      0252    Fri 03 Jul 2015      84082679
      0252    Fri 24 Jul 2015      89400396
      0253    Fri 03 Jul 2015      29038894
      0253    Fri 24 Jul 2015      31367348
      071    Fri 03 Jul 2015      18594024
      071    Fri 24 Jul 2015      18887643
      072    Fri 03 Jul 2015      20141235
      072    Fri 17 Jul 2015      19573266
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-09
        • 1970-01-01
        • 1970-01-01
        • 2015-05-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-08
        相关资源
        最近更新 更多