【问题标题】:Delete lines before and after a match in bash (with sed or awk)?删除 bash 中匹配前后的行(使用 sed 或 awk)?
【发布时间】:2012-08-01 09:31:52
【问题描述】:

我正在尝试从充满事务的文件中删除模式匹配两侧的两行。 IE。找到匹配然后删除它之前的两行,然后删除它之后的两行,然后删除匹配。将其写回原始文件。

所以输入数据是

D28/10/2011
T-3.48
PINITIAL BALANCE
M
^

我的模式是

sed -i '/PINITIAL BALANCE/,+2d' test.txt

但是,这只是在模式匹配后删除两行,然后再删除模式匹配。我无法找到任何合乎逻辑的方法来使用 sed 从原始文件中删除所有 5 行数据。

【问题讨论】:

    标签: shell sed awk


    【解决方案1】:

    一个更简单易懂的解决方案可能是:

    awk '/PINITIAL BALANCE/ {print NR-2 "," NR+2 "d"}' input_filename \
        | sed -f - input_filename > output_filename
    

    awk 用于创建一个 sed 脚本,删除相关行并将结果写入 output_filename。

    这使用了两个可能比其他答案效率低的过程。

    【讨论】:

      【解决方案2】:

      对于这样的任务,我可能会使用更高级的工具,比如 Perl:

      perl -ne 'push @x, $_;
                if (@x > 4) {
                    if ($x[2] =~ /PINITIAL BALANCE/) { undef @x }
                        else { print shift @x }
                }
                END { print @x }' input-file > output-file
      

      这将从输入文件中删除 5 行。这些行将是匹配前的 2 行、匹配的行和之后的两行。您可以通过修改 @x > 4 (这将删除 5 行)和正在匹配的行修改 $x[2] 更改要删除的总行数(这会使第三行上的匹配被删除,因此在匹配之前删除两行)。

      【讨论】:

      • 感谢 choroba 的建议。我以前从未在 Perl 中编程过……在 bash 中没有办法做到这一点吗?
      • 如果可能的话,在 bash 中也是可能的。但这不值得努力......
      【解决方案3】:

      sed 会做到的:

      sed '/\n/!N;/\n.*\n/!N;/\n.*\n.*PINITIAL BALANCE/{$d;N;N;d};P;D'
      

      它是这样工作的:

      • 如果 sed 在模式空间中只有一个字符串,它会加入另一个字符串
      • 如果只有两个,则加入第三个
      • 如果它使用 BALANCE 匹配 LINE + LINE + LINE 模式,它会连接两个后续字符串,删除它们并从头开始
      • 如果没有,它会打印 pattern 中的第一个字符串并将其删除,然后从头开始而不滑动 pattern 空间

      为了防止第一个字符串出现模式,您应该修改脚本:

      sed '1{/PINITIAL BALANCE/{N;N;d}};/\n/!N;/\n.*\n/!N;/\n.*\n.*PINITIAL BALANCE/{$d;N;N;d};P;D'
      

      但是,如果您在字符串中有另一个 PINITIAL BALANCE 将被删除,则它会失败。但是,其他解决方案也失败了 =)

      【讨论】:

        【解决方案4】:

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

        sed ':a;$q;N;s/\n/&/2;Ta;/\nPINITIAL BALANCE$/!{P;D};$q;N;$q;N;d' file
        

        【讨论】:

          【解决方案5】:

          将此代码保存到文件grep.sed

          H
          s:.*::
          x
          s:^\n::
          :r
          /PINITIAL BALANCE/ {
              N
              N
              d    
          }
          
          /.*\n.*\n/ {
              P
              D
          }
          x
          d
          

          然后运行这样的命令:

          `sed -i -f grep.sed FILE`
          

          你可以这样使用它:

          sed -i 'H;s:.*::;x;s:^\n::;:r;/PINITIAL BALANCE/{N;N;d;};/.*\n.*\n/{P;D;};x;d' FILE
          

          【讨论】:

          • N;N;d 之前在/bar/ 块内添加$d,如果bar 字符串是最后一个字符串,它将非常有用。
          【解决方案6】:

          一个 awk 单行程序可以完成这项工作:

          awk '/PINITIAL BALANCE/{for(x=NR-2;x<=NR+2;x++)d[x];}{a[NR]=$0}END{for(i=1;i<=NR;i++)if(!(i in d))print a[i]}' file
          

          测试:

          kent$  cat file
          ######
          foo
          D28/10/2011
          T-3.48
          PINITIAL BALANCE
          M
          x
          bar
          ######
          this line will be kept
          here
          comes
          PINITIAL BALANCE
          again
          blah
          this line will be kept too
          ########
          
          kent$  awk '/PINITIAL BALANCE/{for(x=NR-2;x<=NR+2;x++)d[x];}{a[NR]=$0}END{for(i=1;i<=NR;i++)if(!(i in d))print a[i]}' file
          ######
          foo
          bar
          ######
          this line will be kept
          this line will be kept too
          ########
          

          添加一些解释

            awk '/PINITIAL BALANCE/{for(x=NR-2;x<=NR+2;x++)d[x];}   #if match found, add the line and +- 2 lines' line number in an array "d"
                {a[NR]=$0} # save all lines in an array with line number as index
                END{for(i=1;i<=NR;i++)if(!(i in d))print a[i]}' #finally print only those index not in array "d"
               file  # your input file
          

          【讨论】:

          • 感谢 awk oneliner Kent。这看起来真的很复杂。如果您能提供一点解释,那就太棒了?
          • @juliushibert 添加了简短说明
          猜你喜欢
          • 2012-12-10
          • 1970-01-01
          • 2012-02-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-02-02
          • 2017-01-10
          相关资源
          最近更新 更多