在这编辑
斯蒂芬·查泽拉斯 POSIX 化 (再次)我sed
通过插入-e
xpression 中断和另一个-e
xpression 语句进行格式化。现在,我想我可能会在评论中问他为什么,但该答案已经是第 18 版,而且几乎所有之前的答案都已经感谢类似的免费赠品(如果你能看到被删除的评论你就会明白我的意思)。还有,我思考我已经足够理解为什么要以一种可能更普遍有用的方式来表达这一点。所以这里希望...
如果可能的话,我通常更愿意将我的总sed
-e
表达保持为 1,但我也更倾向于遵循规格尽可能接近,特别是当差异不超过 a<space>
和 an时-e
。但如果我不明白我就无法做到这一点为什么我应该。以下是我目前的理解的简要概述:
中断
' -e '
可以便携式地代替命令行语句中的sed
脚本\n
ewline中断...sed
我承认我很模糊为什么sed
{
函数中的右大括号}
前面必须有一个\n
ewline 中断,如下所示:- The
<right-brace>
前面应有 a,<newline>
并且前面或后面可以有<blank>
字符。
- The
\n
在任何使用...之后同样需要一个ewline 中断a
,b
,c
,i
,r
,t
,w
, 或者:
。
但我不清楚{
函数}
定义与!
not 运算符有何关系。我在规范中发现的唯一提及否定运算符的内容是:
- 函数前面可以有一个或多个
!
字符,在这种情况下,如果地址不选择模式空间,则应应用该函数。
这是否意味着使用 a!
意味着{
大括号}
?命令又如何$!
——它们同样应该用分隔' -e '
符分隔吗?这就是 Stéphane 最近提出的问题吗?POSIX化我的答案?
我认为它要么是!
否定运算符,要么是b
他在编辑中提到的牧场语句 - 或者可能同时是两者 - 但我不知道并且应该这样做。如果是仅有的牧场b
声明,那么我相信ad
会代替它并消除' -e '
休息的需要,但我宁愿在冒险三次之前确定一下POSIX化回答。你能帮我吗?
我确实冒险了毕竟,但没有任何确定性......
答案1
所以现在是这个问题得到答案的时候了,尽管我最终凭直觉得出了答案如何为了在几乎所有情况下正确地做到这一点,前段时间,我直到最近才设法对标准中的文本进行相当具体的理解。实际上,它的表述相当简单——我想,我只是愚蠢地忽略了它很多次。
文本的相关部分都可以在标题下找到...
-
论点文本应由一行或多行组成。文本中每个嵌入的
\n
行前面应有一个\
反斜杠。文本中的其他反斜杠应被删除,并且后面的字符应按字面意思处理。r
和命令动词w
,以及命令w
的标志s
,采用可选的r文件(或者工作文件) 参数,与命令动词字母或标志分隔一个或多个<blank>s
;实现可以允许零间隔作为扩展。除
{
、a
、b
、c
、i
、r
、t
、w
、:
和之外的命令动词#
可以后跟;
分号、可选的<blank>s
和另一个命令动词。但是,当s
命令动词与标志一起使用时w
,以这种方式在其后面加上另一个命令会产生未定义的结果。
...在...
选项:可以指定多个
-e
和选项。-f
所有命令都应按照指定的顺序添加到脚本中,无论其来源如何。-e
脚本- 添加指定的编辑命令脚本选项参数到结尾脚本编辑命令。这脚本选项参数应具有与选项参数相同的属性脚本操作数,描述于操作数部分。-f
脚本文件- 在文件中添加编辑命令脚本文件到脚本的末尾。
最后在...
操作数:
- 脚本- 用作的字符串脚本编辑命令。申请不得提出脚本这违反了文本文件的限制,除了最后一个字符不必是
\n
ewline 之外。
- 脚本- 用作的字符串脚本编辑命令。申请不得提出脚本这违反了文本文件的限制,除了最后一个字符不必是
因此,当您整体考虑时,任何可以选择后跟任意参数而没有预定义分隔符的命令都是有意义的(与s d sub d repl d flag
例如相反)应在未转义的\n
ewline 处定界。
值得商榷的是;
是预定义的分隔符,但在这种情况下,使用;
for 任何[aic]
命令都需要在专门针对这三个命令的实现中包含单独的解析器 - 例如,与用于 的解析器分开[:brw]
。否则实施就必须要求;
还在反斜杠内转义文本参数,并且从那时起它只会变得更加复杂。
如果我正在编写一个sed
我希望既兼容又高效的程序,那么我希望我不会编写这样一个单独的解析器 - 除非[aic]
如果不立即跟上\n
ewline,可能会产生语法错误。但这是一个简单的标记化问题 - 结束定界符情况通常是更有问题的情况。我就这么写:
sed -e w\ file\\ -e one -e '...;and more commands'
...和...
sed -e a\\ -e appended\\ -e text -e '...;and more commands'
...的行为非常相似,因为第一个将创建并写入名为的文件:
file
one
...第二个会将文本块附加到输出的当前行,例如...
appended
text
...因为两者将共享相同的参数解析代码。
关于这个{ ... }
问题$!
——好吧,我离那里还很远。前面带有地址的单个命令是不是一个函数,而只是一个寻址命令。几乎全部命令 - 包括{
函数定义 }
被指定接受/one/
或/one/,/two/
地址 - 除了#
评论和:
标签定义。地址可以是行号或正则表达式,并且可以用 取反!
。所以所有的...
$!d
/address/s/ub/stitution/
5!y/d/c/
...根据标准可以跟随一个;
或多个命令,但如果单个地址需要更多命令,并且在执行每个命令后不应重新评估该地址,则应使用如下{
函数:}
/address/{ s//replace addressed pattern/
s/do other conditional/substitutions/
s/in the same context/without/
s/reevaluating/address/
}
...{
在同一行中不能跟有结束语,并且除了在行的开头之外不能发生}
结束语。}
但是,如果包含的命令不应后跟 ewline \n
,则它也不需要在函数内。因此,上述所有s///
替换 - 甚至右大}
括号,都可以方便地后跟;
分号和其他命令。
我一直在谈论\n
ewline 分隔符,但我知道问题是关于-e
表达式语句。但这两者实际上是同一的,关键的关系是脚本可以是文字命令行参数或带有其中之一的文件-[ef]
,并且两者都被解释为文本文件(指定以\n
ewline 结尾)但实际上都不需要结尾在一条\n
线上。这样我就可以合理地(我希望)推断\0NUL
分隔参数意味着结束\n
ewline,并且所有调用参数都得到至少)无论如何,一个\0NUL
分隔符,那么任何一个都应该可以正常工作。
事实上,在实践中,除了标准指定\
反斜杠转义换行符之外的每种情况,我都发现了......
sed -e ... -e '...\' -e '...'
...也能工作。在每种情况下 - 再次,在实践中 -\n
应该需要非转义的ewline ......
sed -e '...' -e '...'
...也为我工作过。我上面提到的一个例外是......
sed -e 's/.../...\' -e '.../'
...这不适用于我的任何测试中的任何实现。我相当确定这会回到文本文件要求和事实s///
来了带有分隔符,因此单个语句没有理由跨越\0NUL
分隔参数。
因此,总而言之,这里是编写几种sed
命令的可移植方法的简短概述:
对于任何一个[aic]
:
...commands;[aic]\
text embedded newline\
delimiting newline
...more;commands...
...或者...
sed -e '...commands;[aic]\' -e 'text embedded newline\' -e 'delimiting newline' -e '.;.;.'
对于任何[:rwtb]
地方范围是选修的 (对于除 之外的所有人:
)但分隔线\n
是不是。请注意,我从来没有理由尝试多行标签与 一起使用的参数[:tb]
,但是w
riting/r
指向多行[rw]文件sed
只要嵌入的\n
ewline 用反斜杠转义,参数通常会被我测试过的 s 毫无疑问地接受\
。尽管如此,该标准并没有直接规定标签和[rw]文件参数应该被同样地解析为文本参数,并且没有提及\n
关于前两个的 ewlines,除非它界定了它们。
...commands;[:trwb] parameter
...more;commands...
...或者...
sed -e '[:trwb] parameter' -e '...'
...其中<space>
上述对于 是可选的[:tb]
。
最后...
...;address[!]{ ...function;commands...
};...more;commands....
...或者...
sed -e '...;address[!]{ ...function;commands...' -e '};...more;commands...'
...其中任何上述命令(除外:
)也接受至少一个地址并且它可以是/
正则表达式/
或行号,并且可以用 取反!
,但是如果单个评估需要多个命令地址那么必须使用{
函数上下文分隔大括号。}
一个函数甚至可以包含多个\n
ewline 分隔的命令,但每个命令都必须在大括号内分隔,否则会如此。
这就是编写可移植脚本的方法sed
。