sed忽略了不匹配的行


91

如何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忽略输入中不匹配的行。那么我们该怎么做呢?


2
接受的答案应该是mouviciel提出的答案:stackoverflow.com/a/1665574/869951
Oliver,

Answers:


89

使用普通sed的另一种方法:

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

s///是一个替换,t没有任何标签时有条件地跳过所有以下命令,d删除行。

不需要perl或grep。

(根据尼古拉斯·莱利的建议编辑)


3
在OS X 10.8.2,我不得不分开tx,并d以换行符而不是我得到一个分号undefined label 'x;d;:x'
davidchambers 2012年

6
更好的是:(sed -e 's/.../.../' -e 'tx' -e 'd' -e ':x'建议对类似问题进行评论)。
davidchambers 2012年

1
如果没有提供标签,则“ t”将转移到脚本的末尾,因此更简单:sed -e 's/.../.../' -e 't' -e 'd'
Nicholas Riley

人们不了解-e选项的含义,因此一般不要提及它。
Fredrick Gauss

241

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

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

这给出:

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

3
这种方法的一个缺点是,如果您有多个匹配的表达式,则结果也会被多次打印。例如: echo foo | sed -n -e 's/foo/bar/p' -e 's/bar/oof/p'将同时输出baroof在单独的行上输出。尽管goto-label不能同时处理多个模式,因为如果第一个模式不匹配,它将删除该行。
拉普西

@Rapsey是因为您告诉它打印两次。在单个sed命令中,您已告诉它要打印两次,每个实例都在原位打印(或缓冲)。您要么必须用管道代替-e,要么仅在最后一个-e上加上“ p”。
微生物

@Rapsey:看到我对这个相关问题的回答
Amessihel

@microbial,它不起作用,因为最后一个替换表达式的最后一个p标志将在每个匹配的行上起作用。
Amessihel



0

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

  • 首先,引用Unix SE的答案,您可以“在大多数sed命令前面加上地址以限制它们所应用的行数”。
  • 其次,您可以将花括号内的命令分组{}(用分号;或换行分隔)
  • 第三,在最后一次替换上添加打印标志p

句法:

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

示例(有关更多详细信息,请参见此处文档):

  • 码:

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

    kaka
    
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.