【问题标题】:Have sed ignore non-matching lines已 sed 忽略不匹配的行
【发布时间】:2010-12-12 12:58:28
【问题描述】:

如何使sed 根据某些表达式过滤匹配行,但忽略不匹配的行,而不是让它们打印?

作为一个真实的例子,我想在一组文件上运行scalac(Scala 编译器),并从其-verbose 输出中读取创建的.class 文件。 scalac -verbose 输出一堆消息,但我们只对[wrote some-class-name.class] 形式的消息感兴趣。 我目前正在做的是(|& 是 bash 4.0 将 stderr 传递到下一个程序的方式):

$ scalac -verbose some-file.scala ... |& sed 's/^\[wrote \(.*\.class\)\]$/\1/'

这将从我们感兴趣的消息中提取文件名,但也会让所有其他消息原封不动地通过!当然我们可以这样做:

$ scalac -verbose some-file.scala ... |& grep '^\[wrote .*\.class\]$' |
  sed 's/^\[wrote \(.*\.class\)\]$/\1/'

这很有效,但看起来很像解决真正的问题,即如何指示sed 忽略输入中的不匹配行。那么我们该怎么做呢?

【问题讨论】:

标签: sed


【解决方案1】:

如果不想打印不匹配的行,可以使用组合

  • -n 告诉 sed 不要打印的选项
  • p 标志告诉 sed 打印匹配的内容

这给出了:

sed -n 's/.../.../p'

【讨论】:

  • 这种方法的一个缺点是如果你有多个匹配的表达式,结果也会被打印多次。例如:echo foo | sed -n -e 's/foo/bar/p' -e 's/bar/oof/p' 将在不同的行上同时输出 baroof。虽然 goto-label 品种也不能处理多个模式,因为如果第一个模式不匹配,它将删除该行。
  • @Rapsey 那是因为你告诉它打印两次。在您告诉它打印两次的单个 sed 命令中,每个实例都在原位打印(或者可能是缓冲的)。您要么必须使用管道而不是 -e,要么只将“p”放在最后一个 -e 上。
  • @microbial,它不起作用,因为最后一个 p 标志将在最后一个替换表达式在每个匹配的行上起作用。
【解决方案2】:

普通 sed 的另一种方式:

sed -e 's/.../.../;t;d'

s/// 是一个替代,t 没有任何标签有条件地跳过所有后续命令,d 删除行。

不需要 perl 或 grep。

(根据 Nicholas Riley 的建议编辑)

【讨论】:

  • 在 OS X 10.8.2 上,我不得不用换行符而不是分号分隔 txd,因为我得到了 undefined label 'x;d;:x'
  • 更好:sed -e 's/.../.../' -e 'tx' -e 'd' -e ':x'(建议在 similar question 上发表评论)。
  • 如果没有提供标签,'t' 将转移到脚本的末尾,所以更简单:sed -e 's/.../.../' -e 't' -e 'd'
  • 人们不知道-e选项的含义,所以一般不提。
  • 未定义标签'd'
【解决方案3】:

使用 Perl:

... |& perl -ne 'print "$1\n" if /^\[wrote (.*\.class)\]$/'

【讨论】:

    【解决方案4】:

    Rapsey 提出了关于多重替换表达式的相关观点。

    • 首先,quoting an Unix SE answer,您可以“在大多数 sed 命令前加上地址,以限制它们适用的行”。
    • 其次,您可以在花括号{}内对命令进行分组(用分号;或换行符分隔)
    • 第三,在最后一个替换上添加打印标志p

    语法:

    sed -n -e '/^given_regexp/ {s/regexp1/replacement1/flags1;[...];s/regexp1/replacement1/flagsnp}'
    

    示例(详情请参阅Here document):

    • 代码:

      sed -n -e '/^ha/ {s/h/k/g;s/a/e/gp}' <<SAMPLE
      haha
      hihi
      SAMPLE
      
    • 结果:

      keke
      

    【讨论】:

      【解决方案5】:
      sed -n '/.../!p'
      

      不需要替换。

      【讨论】:

      • sed '/.../ d' 用于删除确实匹配的行
      猜你喜欢
      • 1970-01-01
      • 2017-01-31
      • 2021-07-03
      • 1970-01-01
      • 2016-11-28
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      相关资源
      最近更新 更多