【问题标题】:remove 2 consecutive lines删除 2 个连续的行
【发布时间】:2013-11-06 06:21:15
【问题描述】:

我有以下格式的数据:

#@ <id_wxyz_1>
A line written after this.

#@ <id_123>
A line written after this one also.

#@ <id_wxyz_2>
One more line.

#@ <id_yex_9>
Another line.

现在我想删除 2 行:#@ <...> 中包含“wxyz”的行及其下一行。我想要的示例输出是:

#@ <id_123>
A line written after this one also.

#@ <id_yex_9>
Another line.

是否有一些 linux 命令也可以实现相同的功能,或者在 python 中是否有一些有效的方法来实现相同的功能。我知道我可以使用 grep、sed 等有选择地删除一行。但是是否可以使用 linux 命令有选择地删除 2 个连续的行

编辑:给出的答案非常好,但它们不适用于以下形式的输入:

#@ <id_wxyz_1>
A line written after this.

#@ <id_wxyz_2>
A line written after this.

#@ <id_wxyz_3>
A line written after this.

#@ <id_wxyz_4>
A line written after this.

#@ <id_wxyzadded5>
A line written after this.

对于上述输入,我应该没有输出行。

再次编辑:我拥有的另一组输入是:

#@ <id_wxyz0>
Line 1.
#@ <id_wxyz1>
line 2.
#@ <id_wxyz2> 
line 3.
#@ <id_wxyz3> 
line 4.
#@ <id_6>
line 5.

输出应该是什么

#@ <id_6>
line 5.

【问题讨论】:

  • 考虑同时使用GNU awk...
  • 您可以编写一个 Perl 脚本,扫描每一行以查找模式 _wxyz_,然后删除该行和下一行。没有一个单一的unix“命令”可以做这样的事情。当涉及到多行操作时,我推荐 Perl 而不是 sed 或 awk 等实用程序

标签: python regex linux ubuntu sed


【解决方案1】:

您可以使用 sed by 来执行此操作,例如。

/^#@ <.*wxyz.*>/ {
   N        #Add the next line to the pattern space
   s/.*//   #clear the line
   N        #Read another line
   /^\n$/ d #if line was blank, delete and start next cycle (reading again)
   D        #Otherwise, delete up to newline, and start next cycle with that

}

注意:对于第二种情况,它实际上仍然输出一个空行

【讨论】:

  • 你的回答太棒了。为此+1。但它不适用于问题中提到的某些输入
  • @JannatArora:已修复(虽然现在没那么简单了,很遗憾)。顺便说一句,如果情况确实是连续 2 行,并且您使用的是 GNU sed,那么您可以使用 /^#@ &lt;.*wxyz.*&gt;/,+1 d 而不是这种混乱。
【解决方案2】:

您也可以简单地使用grep

示例:根据您的输入

$ cat t
#@ <id_wxyz_1>
A line written after this.

#@ <id_123>
A line written after this one also.

#@ <id_wxyz_2>
One more line.

#@ <id_yex_9>
Another line.

#@ <id_wxyz_1>
A line written after this.

#@ <id_wxyz_2>
A line written after this.

#@ <id_wxyz_3>
A line written after this.

#@ <id_wxyz_4>
A line written after this.

#@ <id_wxyzadded5>
A line written after this.

#@ <id_wxyz0>
Line 1.
#@ <id_wxyz1>
line 2.
#@ <id_wxyz2> 
line 3.
#@ <id_wxyz3> 
line 4.
#@ <id_6>
line 5.

你可以跑

$ grep -A1  --group-separator=""  -P '#[^_]*((?!wxyz).)*$' t
#@ <id_123>
A line written after this one also.

#@ <id_yex_9>
Another line.

#@ <id_6>
line 5.

正则表达式匹配以# 开头但不包含wxyz 的行,语法类似于Perl(因此有-P 参数)。 -A1 在匹配后添加一行到输出。未记录的--group-separator="" 选项替换了默认的--,后者在使用-A(或B-C)选项时通常分隔行组。请注意,后一个选项并非在所有实现中都可用。

【讨论】:

    【解决方案3】:

    使用awk 你可以说:

    awk '/^#@ <.*wxyz.*>/{getline;getline}1' filename
    

    编辑:根据您修改后的问题,您可以说:

    sed '/^#@ <id_wxyz.*/,/^$/d' filename
    

    【讨论】:

    • 您好,这不适用于以下形式的输入:#@ 在此之后写入的一行。 #@ 写在这之后的一行。 #@ 写在这之后的一行。 #@ 写在这之后的一行。 #@ 写在这之后的一行。
    • @JannatArora 看来您的输入已更改。评论不保留换行符;如果你更新你的问题会更好。
    • @JannatArora 建议的sed 选项可能对您有用;见编辑。
    • 感谢您的帮助。但它不适用于我在问题中提到的表单输入(再次编辑)
    • awk 应该是getline;next,后面的行可以匹配。
    【解决方案4】:

    您也可以使用。当它匹配该行时,使用getline 两次用于以下两行并使用next 避免打印它们。

    awk '/^#@[[:blank:]]+<.*wxyz.*>/ { getline; getline; next } { print }' infile
    

    它产生:

    #@ <id_123>
    A line written after this one also.
    
    #@ <id_yex_9>
    Another line.
    

    UPDATEOP 的新编辑提供解决方案:

    awk  '
        BEGIN { RS = "#@" } 
        $1 ~ /[^[:space:]]/ && $1 !~ /<.*wxyz.*>/ { 
            sub(/\n[[:blank:]]*$/, "")
            print RS, $0 
        }
    ' infile
    

    你的最后一个例子产生了:

    #@  <id_6>
    line 5.
    

    【讨论】:

    • 你的回答太棒了。为此+1。但它不适用于问题中提到的某些输入
    • getlines 太多。你只需要一个({print} 可以是1)。
    猜你喜欢
    • 2019-09-12
    • 2013-12-16
    • 1970-01-01
    • 2016-08-17
    • 2020-03-30
    • 2023-03-10
    • 2016-09-02
    • 2017-07-28
    • 2015-06-14
    相关资源
    最近更新 更多