我完全困惑为什么我不能用 ed 打印这个范围当有两个范围时-看文件2.tf文件-;但我可以在只有时打印一个范围-看文件1.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:该??
方法实际上并没有按预期工作(如果有三个部分像文件3.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"
}
答案1
导致问题的ed
和之间的区别在于正则表达式地址范围的处理方式。sed
在 中sed
,首先找到起始行,然后将命令应用于所有行,直到找到结束行。
ed
另一方面,在 中,范围的起始线和终止线是相对于当前行计算的。然后该命令将应用于该行范围内的所有行。
/module.*again/, /}/
在使用in和第二个文件的情况下ed
,当前行位于文件的末尾(因为您刚刚将其加载到缓冲区中)。该范围的起始行计算为第 7 行,结束行为第 4 行(当前行之后与第二个表达式匹配的第一行)。您不能有一个向后运行的范围,因此您会收到错误。
使用 时?module.*again?, ?}?
,搜索会反向进行,因此范围的起始位置与之前一样计算为第 7 行(只有一行与表达式 匹配module.*again
),但现在范围的末尾是第 9 行,该行大于 7,所以你没有同样的问题。
你的解决方案是不是?
通过使用in 代替正则表达式分隔符来反转搜索/
,因为这将无法正确找到三个部分的中间部分(示例中只有两个部分)。相反,首先将光标移动到该范围的第一行,然后将命令从该行应用到该部分的末尾:
/module.*again/; /}/ p
这看起来与 非常相似/module.*again/, /}/ p
,但通过使用;
代替,
,在找到起始地址之前不会计算结束地址。这是sed
默认处理范围的方式,因为它没有其他选择(不将完整文档存储在内存中)。
该表达式本质上与较长的表达式相同,后者显式地将光标移动到范围的开头,然后将命令从现在的当前行应用到该部分的末尾:
/module.*again/; ., /}/ p
POSIX 规范ed
,
关于vs说的是;
:
<comma>
地址之间应使用(,
) 或<semicolon>
字符 ( )分隔;
。如果有<semicolon>
分隔符,则将当前行(.
)设置为第一个地址,然后才计算第二个地址。此功能可用于确定向前和向后搜索的起始行。