因此,这通常是一个问题的答案,尽管虽然我最终在一段时间前几乎每个情况下都能直观地弄清楚如何正确执行此操作,但直到最近我才设法通过标准中的文本相当具体地理解这一点。 。实际上,它的表达相当简单-我想我愚蠢地忽略了它很多次。
文本的相关部分均在标题下找到...
在中编辑命令sed:
参数文本应由一行或多行组成。\n文本中每个嵌入的ewline之前应加\反斜杠。文本中的其他反斜杠应被删除,并且以下字符应按原义对待。
的r和w命令动词,并w标志提供给s命令,采取可选的RFile(或wfile)参数,从动词字母或标志的命令分离由一个或多个<blank>s; 实现可以允许零分隔作为扩展。
命令谓词以外{,a,b,c,i,r,t,w,:,和#可以跟一个;分号,可选的<blank>s,和另一个命令动词。但是,当s命令动词与w标志一起使用时,以这种方式在其后跟另一个命令将产生未定义的结果。
...在...
最后...
操作数:
- 脚本 -用作编辑命令脚本的字符串。该应用程序不应提供违反文本文件限制的脚本,除非最终字符不必是
\n斜线。
因此,当您将其全部考虑在内时,有意义的是,任何可选的后跟任意参数且没有预定义定界符(s d sub d repl d flag例如,\n与之相反)的命令都应在未转义的ewline 处定界。
可以争论的是,s ; 是预定义的定界符,但在这种情况下,将;for [aic]命令用于任何命令将需要在实现中包括专门用于这三个命令的单独的解析器- [:brw]例如,与用于的解析器分离。否则,实现将不得不要求在text参数中; 也将反斜杠转义,并且从那以后只会变得越来越复杂。
如果我写的sed是我希望既合规又高效的程序,那么我不会写这样一个单独的解析器-除非可能会[aic]产生语法错误(如果没有紧随其后的是\n斜线)。但这是一个简单的令牌化问题-结束定界符的情况通常是问题更大的情况。我只是这样写:
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
...因为两者将共享相同的参数解析代码。
关于{ ... }and $!问题-好吧,我已经走了。带有地址的单个命令不是功能,而只是寻址的命令。除注释和标签定义外,几乎所有命令(包括{ 函数定义) }都指定为接受/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/
}
...在{同一行上不能跟一个结束符,}并且}除非在行的开头,否则不能发生一个结束符。但是,如果所包含的命令不应在其后跟随\newline,则它也不必在函数内。因此,上述所有s///障碍-甚至是右}括号,都可以随身携带;分号和其他命令。
我一直在谈论\newline分隔符,但-e我知道的问题是关于xpression语句的。但是两者实际上是相同的,并且关键的关系是,脚本可以是文字命令行参数,也可以是带有或的文件-[ef],并且两者都被解释为文本文件(指定为以a结尾\newline),但也需要实际结束在\newline。这样,我可以合理地(我希望)推断出一个\0NUL定界的参数暗示着结尾的\newline,并且由于所有调用参数至少都得到一个\0NUL定界符,所以无论哪种都可以正常工作。
实际上,实际上,在任何情况下,除了标准指定了\反斜杠转义换行符的情况外,我都很好地发现了……
sed -e ... -e '...\' -e '...'
...工作也一样。而且,在每种情况下-在实践中- \n都应要求使用不漏电的大绳...
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]地方的参数是可选的 (为所有,但:),但分界\newline是不是。请注意,我从未有过一个理由去尝试多线标签参数将与被使用[:tb],但writing / reading在多行[RW]文件参数通常是毫无疑问的接受了sed这么久,我已经测试作为嵌入式\newline带\反斜杠转义。尽管如此,该标准仍未直接指定应将label和[rw] file参数解析为与text相同参数,\n除了前两个定界线外,没有提及前两个定线。
...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行分隔符分隔的命令,但是每个命令都必须在花括号内定界,否则会如此。
这就是编写可移植sed脚本的方法。
b;n;:b,您可以跳转到";n;:b"历史记录和POSIX sed中调用的标签(而GNU sed不在此范围内)。