请解释一下 sed 脚本

请解释一下 sed 脚本

我无法理解这个 sed 脚本是如何工作的:

echo -e "Line #1\n\n\n\nLine #2\n\n\nLine #3" | sed '1s/^$//p;/./,/^$/!d'

它会抑制重复的空行,例如cat -s “但是我有几个问题”:

  1. 为了什么1s/^$//p?据我了解,即使第一行为空,它也不执行任何操作
  2. 这是否只在第一个喜欢/./,/^$/之前匹配而不匹配?^$Line #1\n\nLine #1\n\n\n
  3. sed 中默认范围不是贪婪的吗?

为了澄清问题 3,我尝试了接下来的测试:

echo -e "Line #1\n\n\n\nLine #2\n\n\nLine #3" | sed -n '/#/,/#/p'

结果是:

Line #1



Line #2
Line #3

(所以,它是贪婪的)

但是当我尝试时:

echo -e "Line #1\n\n\n\nLine #2\n\n\nLine #3" | sed -n '/#1/,/#/p'

结果是:

Line #1



Line #2

(现在看来是不贪心了)

答案1

1s/^$//p如果第一行为空,则打印第一行。

/./,/^$/匹配从第一个非空行到遇到的第一个空行的行。从正则表达式限定符的意义上来说,它不是贪婪的:sed无法向前查看文件或回溯,因此它必须在结束模式第一次匹配时停止。

在结束行之后,再次开始搜索起始行,因此下一个非空行再次开始范围。实际上,范围匹配连续的非空行,加上后面的第一个空行。

由于范围被用作/./,/^$/!d,因此所有不匹配的行都将被删除。这包括第一行(如果它是空的),这就是为什么第一条规则显式打印它的原因。

如果没有1s/^$//p规则,第一行如果为空就会被删除,即使它并不是真正的“重复”。

$ echo $'\nfoo' | sed '1s/^$//p;/./,/^$/!d'

foo
$ echo $'\nfoo' | sed '/./,/^$/!d'
foo
$

在您的测试中,范围/#/,/#/有点不同,因为它以相同的模式开始和结束。Line #1匹配开始模式,(因此打印中间的空行)Line #2匹配结束模式,(后面的空行不是)并且 on Line #3,范围再次开始。

在另一个中,起始模式是/#1/,但仅在输入中找到一次。

答案2

ilkkachu 给出了一个很好的答案,涵盖了该命令的各个方面,包括对 sed 字符串第一部分的不太明显的需求;并包括“!”这一事实字符删除不匹配的部分,实际上是重复的空行。

尽管如此,当有更简单的选择时,这仍然是一种奇怪的方法,例如更多-s, 或者独特的可用的。

相关内容