缩进 sed 的 'i\' 命令的参数是否可移植?

缩进 sed 的 'i\' 命令的参数是否可移植?

我的印象是POSIX 规范sedi\除非您希望输出中出现前导空格,否则有必要将命令后面的行上的文本左对齐。

在我的 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

不,但是只要您转义任何前导空白,您的脚本就可以移植。为什么 ?因为有些seds 会从文本行中去除空白字符,而避免这种情况的唯一方法是转义前导空白,正如这些上世纪的手册页所解释的那样:1,2,3
这同样适用BSD sedOSX只是复制了代码,这不是他们的扩展名),如果您检查档案并阅读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 中:aic

$ 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

相关内容