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 はテキスト行から空白文字を削除し、それを回避する唯一の方法は先頭の空白をエスケープすることであるためです。これは、前世紀に遡るこれらのマニュアル ページで説明されています。123
BSD sedOSXコードをコピーしただけで、拡張機能ではありません)アーカイブをチェックして読んでみれば 、manページからBSD 2.11それはかなり明白です:

(1)i\
文章
.......
引数は文章1 行以上の行で構成され、最後の行を除くすべての行は'\'改行を隠すために で終わります。テキスト内のバックスラッシュは、コマンドの置換文字列内のバックスラッシュと同様に扱われ's' 、スクリプトの各行で行われる削除から最初の空白とタブを保護するために使用できます。

さて、POSIX仕様のどこにこれが記載されているのでしょうか?そこにはこう書いてあるだけです

引数テキストは 1 行以上で構成されます。テキストに埋め込まれた各 <newline> の前には <backslash> が付きます。テキスト内のその他の <backslash> 文字は削除され、次の文字は文字どおりに扱われます。

そして下にスクロールすると根拠それは言う

コマンドラインで <blank> および <space> 文字を受け入れるための要件は、以前の提案よりも明確にされました。これは、歴史的慣行を明確に記述し、sed ユーティリティのテキスト記述の歴史的ドキュメントの多くに見られる「スクリプトの各行で行われる削除から最初の空白とタブを保護する」というフレーズに関する混乱を排除するためです。(すべての実装でテキスト行から <blank> 文字が削除されたわけではありませんが、コマンドラインのアドレスの前に先頭の <blank> 文字があることは許可されています。)

の部分から「バックスラッシュは、次の場合に使用できます」その引用文には含まれていなかったが、残りのフレーズ「最初の空白を保護する...」意味が分からない... 1


とにかく、まとめると、いくつかの実装ではテキスト行から空白を削除していました(そしていくつかは今でも削除しています)。しかし、すべての実装が準拠すべきPOSIX仕様では、

テキスト内の他の <backslash> 文字は削除され、次の文字は文字通りに扱われます。

挿入するテキストの行をインデントする移植可能な方法は、各行の先頭の空白をエスケープすることであると結論付けることができます。


1: また、ソース コードを変更せずにページ内の段落全体を変更した理由OSXもわかりません。以前と同じ動作が得られますが、この内容を文書化した man セクションはもう存在しません。BSDman

答え2

これはOSXのsed拡張機能であり、標準的な動作ではありません。このリンクは、機能上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、 、\を使用すると行継続文字として誤って処理される可能性がありa、動作はさらに奇妙になります。私の FreeBSD 9.3 では次のようになりますic

$ 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

関連情報