縮排 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

相關內容