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