我完全困惑为什么当有两个范围时我不能用 ed 打印这个范围- 请参阅file2.tf文件 - ;但当只有一个范围时我可以打印- 请参阅file1.tf文件 - 并且我可以使用 gsed (macOS 上的 GNU sed)命令进行打印;但我无法用 ed 打印。请考虑我的 shell 会话并澄清我的误解:
$ ed -s file1.tf <<<',n'
1 # some comment
2 module "hello_world" {
3 source = "./mydir"
4 }
5 # another comment
$ ed -s file1.tf <<<'/module.*world/,/}/p'
module "hello_world" {
source = "./mydir"
}
$ ed -s file2.tf <<<',n'
1 # some comment
2 module "hello_world" {
3 source = "./mydir"
4 }
5 # another comment
6 # some comment
7 module "hello_again" {
8 source = "./anotherdir"
9 }
10 # another comment
$ ed -s file2.tf <<<'/module.*again/,/}/p'
?
$ gsed -n '/module.*again/,/}/p' file2.tf
module "hello_again" {
source = "./anotherdir"
}
更新:相反方向有效;但我不知道为什么:
$ ed -s file2.tf <<<'?module.*again?,?}?p'
module "hello_again" {
source = "./anotherdir"
}
更新 2:该??
方法实际上并没有按预期工作(如果有像file3.tf文件示例中那样的三个部分),请参阅答案以获取解释。
$ ed -s file3.tf <<<,n
1 # some comment
2 module "hello_world" {
3 source = "./mydir"
4 }
5 # another comment
6 # some comment
7 module "hello_again" {
8 source = "./anotherdir"
9 }
10 # another comment
11 # some comment
12 module "hello_yet_again" {
13 source = "./yetanotherdir"
14 }
15 # another comment
$ ed -s file3.tf <<<'?module.*hello_again?,?}?p'
module "hello_again" {
source = "./anotherdir"
}
# another comment
# some comment
module "hello_yet_again" {
source = "./yetanotherdir"
}
导致问题的
ed
和之间的区别在于正则表达式地址范围的处理方式。sed
在 中
sed
,首先找到起始行,然后将命令应用于所有行,直到找到结束行。另一方面,在 中
ed
,范围的起始线和终止线是相对于当前行计算的。然后该命令将应用于该行范围内的所有行。在使用
/module.*again/, /}/
ined
和第二个文件的情况下,当前行位于文件的末尾(因为您刚刚将其加载到缓冲区中)。该范围的起始行计算为第 7 行,结束行为第 4 行(当前行之后与第二个表达式匹配的第一行)。您不能有一个向后运行的范围,因此您会收到错误。使用 时
?module.*again?, ?}?
,搜索会反向进行,因此范围的起始位置与之前一样计算为第 7 行(只有一行与表达式 匹配module.*again
),但现在范围的末尾是第 9 行,该行大于 7,所以你没有同样的问题。您的解决方案不是通过
?
使用代替作为正则表达式分隔符来反转搜索/
,因为这将无法正确找到三个部分的中间部分(您的示例中只有两个)。相反,首先将光标移动到该范围的第一行,然后将命令从该行应用到该部分的末尾:这看起来非常类似于
/module.*again/, /}/ p
,但是通过使用;
代替,
,在找到起始地址之前不会计算结束地址。这是sed
默认处理范围的方式,因为它没有其他选择(不将完整文档存储在内存中)。该表达式本质上与较长的表达式相同,后者显式地将光标移动到范围的开头,然后将命令从现在的当前行应用到该部分的末尾:
POSIX 规范
ed
,
对于vs.是这么说的;
: