11

我以为我理解 sed 但我想不是。我有以下两个文件,我想用不同的行替换“为什么”和“呵呵”行。根本没有空格。

测试.txt:

hi
why
huh
hi
why
huh

测试2.txt:

1
hi
why
huh
hi
why
huh

以下两个命令给出以下结果:

sed "N; s/<why\/>\n<huh\/>/yo/g" test.txt > out.txt

out.txt:
hi
why
huh
hi
yo

sed "N; s/<why\/>\n<huh\/>/yo/g" test2.txt > out2.txt

out2.txt:
1
hi
yo
hi
why
huh

我对 sed 有什么不了解的地方?为什么两个输出文件都不包含以下内容:

hi
yo
hi
yo
4

3 回答 3

11

你的表达几乎是正确的,但它有两个问题:

  • 如果你想匹配why一个单词,你应该把它放在\<\>周围。你确实把它放在了<周围\/>。所以,第一个修正是:

    $ sed 'N; s/\<why\>\n\<huh\>/yo/g' test.txt
    
  • 但它也不起作用:

    $ sed 'N; s/\<why\>\n\<huh\>/yo/g' test.txt
    hi
    why
    huh
    hi
    yo
    

    为什么它只替换第二对线?好吧,在第一行,N命令将连接whyhi,在模式空间中留下字符串hi\nwhy。该字符串与命令不匹配s///,因此仅打印该行。下一次,您huh在模式空间中有字符串并连接hi到它。就在下一行中,您将why\nhuh在要替换的模式空间中。

    解决方案是仅在当前行为 时才why使用地址 /^why$/连接下一行:

    $ sed '/^why$/ {N; s/\<why\>\n\<huh\>/yo/g}' test.txt
    hi
    yo
    hi
    yo
    
于 2012-06-27T20:25:35.330 回答
4

Brandizzi的回答很好地解释了它没有替换两对线的原因。

但是,如果我们更进一步。假设我们有以下文件,我们想用“pure\nmilk”替换“apple\njuice”。

测试.txt

water water water water 
water water water apple
juice water water apple
juice water water water

模式过滤方式不起作用。

sed '/apple/ {N; s/apple\njuice/pure\nmilk/g}' test.txt 

water water water water
water water water pure
milk water water apple
juice water water water

因为 test.txt 中的第二个苹果,已经被 N 连接到前一行,没有被模式过滤器捕获。

我能想到的一种解决方案是使用分支连接所有行,然后进行替换。

sed ':a;N;$!ba;s/apple\njuice/pure\nmilk/g' test.txt 

water water water water
water water water pure
milk water water pure
milk water water water

它看起来很愚蠢,但我还没有想到更好的方法。

于 2015-11-20T19:41:04.000 回答
1

这应该适用于test.txt文件:

sed '/hi/! { N ; s/why\nhuh/yo/ }' test.txt

它的意思是:

如果在一行中找不到hi(它将是why),请阅读下一行并将其全部替换为yo。否则直接打印(当hi)。

输出:

hi
yo
hi
yo
于 2012-06-27T20:21:34.307 回答