![缩进 sed 的 'i\' 命令的参数是否可移植?](https://linux22.com/image/95309/%E7%BC%A9%E8%BF%9B%20sed%20%E7%9A%84%20'i%5C'%20%E5%91%BD%E4%BB%A4%E7%9A%84%E5%8F%82%E6%95%B0%E6%98%AF%E5%90%A6%E5%8F%AF%E7%A7%BB%E6%A4%8D%EF%BC%9F.png)
我的印象是POSIX 规范sed
i\
除非您希望输出中出现前导空格,否则有必要将命令后面的行上的文本左对齐。
在我的 Mac 上进行的快速测试(使用 BSD sed)表明这可能是不是必要的:
$ cat test.sed
#!/bin/sed -f
i\
This line starts with spaces.
$ echo some text | sed -f test.sed
This line starts with spaces.
some text
$
但是,我似乎无法在任何地方找到此记录。它不在 POSIX 规范中,甚至不在sed
我系统的手册页中。
sed
我可以在我想要移植的脚本中依赖这种行为吗? 它有多便携?
(是否有记录任何地方?)
(额外问题:是否有可能强制sed
在传递给的固定行的开头插入空格i\
?)
答案1
不,但是只要您转义任何前导空白,您的脚本就可以移植。为什么 ?因为有些sed
s 会从文本行中去除空白字符,而避免这种情况的唯一方法是转义前导空白,正如这些上世纪的手册页所解释的那样:1,2,3
这同样适用BSD
sed
(OSX
只是复制了代码,这不是他们的扩展名),如果您检查档案并阅读man
页面来自BSD 2.11
很清楚:
(1)我\
文本
.......
表示的一个参数文本'\'
由一行或多行组成,除了最后一行之外,所有行都以隐藏换行符结尾。文本中的反斜杠被视为's'
命令替换字符串中的反斜杠,并且可用于保护初始空格和制表符免受在每个脚本行上进行的剥离。
现在,这在 POSIX 规范中记录在哪里?它只说
参数文本应由一行或多行组成。文本中每个嵌入的<newline> 前面应有一个<backslash>。文本中的其他<反斜杠>字符应被删除,并且后面的字符应按字面意思处理。
如果你向下滚动到基本原理它说
在命令行中接受 <blank> 和 <space> 字符的要求比早期的提案更加明确,以清楚地描述历史实践并消除对短语“保护初始空白[原文如此]和制表符不被剥离”的混淆这是在每个脚本行上完成的”,出现在 sed 实用程序文本描述的许多历史文档中。 (并非所有实现都已知从文本行中删除 <blank> 字符,尽管它们都允许在命令行上的地址前面使用前导 <blank> 字符。)
由于部分与“反斜杠可以用来”未包含在该引用中,其余短语“保护初始空白...”没有任何意义... 1
不管怎样,总而言之:一些实现确实(有些仍然这样做)从文本行中去除空白。然而,由于所有实现都应遵守的 POSIX 规范规定
文本中的其他<反斜杠>字符应被删除,并且后面的字符应按字面意思处理。
我们可以得出结论,在要插入的文本中缩进行的可移植方法是转义每行的前导空格。
1:我也不明白为什么OSX
/BSD
人们在不更改源代码的情况下更改了man
页面中的整个段落 - 您会得到与以前相同的行为,但记录这些内容的 man 部分不再存在。
答案2
它是 OSXsed
扩展,而不是标准行为。你可以看到此链接在功能上compile_text
:
/*
* Compile the text following an a or i command.
*/
static char *
compile_text()
{
int asize, size;
char *text, *p, *op, *s;
char lbuf[_POSIX2_LINE_MAX + 1];
asize = 2 * _POSIX2_LINE_MAX + 1;
text = xmalloc(asize);
size = 0;
while (cu_fgets(lbuf, sizeof(lbuf))) {
op = s = text + size;
p = lbuf;
EATSPACE();
for (; *p; p++) {
if (*p == '\\')
p++;
*s++ = *p;
}
size
他们用EATSPACE
宏来吃掉空间。
在 FreeBSD 中sed
,当使用, ,时可能会错误地将其\
视为行继续字符,这种行为更加奇怪。在我的 FreeBSD 9.3 中:a
i
c
$ echo 1 | sed -e 'i\ 1'
": extra characters after \ at the end of i command
但:
$ echo 1 | sed -e 'i\
2'
2
1
有效,而且它也会占用空间。
GNU sed
,传家宝sed
就没有这个问题。
答案3
康格姆给出了最佳答案,但为了记录,这里是GNU sed
做:
echo foo | sed 'i\
This line starts with spaces.'
输出:
This line starts with spaces.
foo