Переносимо ли сделать отступ для аргумента команды sed 'i\'?

Переносимо ли сделать отступ для аргумента команды sed 'i\'?

Я был под впечатлением отСпецификации 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странице руководства 's в моей системе.

Могу ли я полагаться на это поведение в sedскриптах, которые я хочу сделать переносимыми? Насколько он портативен?

(Это документировано?в любом месте?)


(Бонусный вопрос: возможно ли вообще принудительно sedвставить пробел в начале фиксированной строки, переданной в i\?)

решение1

Нет, но ваш скрипт будет переносимым, пока вы экранируете любой начальный пробел. Почему? Потому что некоторые seds удаляют пустые символы из текстовых строк, и единственный способ избежать этого — экранировать начальный пробел, как объясняют эти страницы руководства, датируемые прошлым веком:1,2,3
То же самое касается BSD sed( OSXпросто скопировал код, это не их расширение), и если вы проверите архивы и прочитаетеmanстраница изBSD 2.11это довольно ясно:

(1)я\
текст
.......
Аргумент, обозначенныйтекстсостоит из одной или нескольких строк, все, кроме последней, заканчиваются на , '\'чтобы скрыть новую строку. Обратные косые черты в тексте обрабатываются как обратные косые черты в строке замены команды 's' и могут использоваться для защиты начальных пробелов и табуляций от удаления, которое выполняется в каждой строке скрипта.

Итак, где это задокументировано в спецификации POSIX? Там сказано только:

Текст аргумента должен состоять из одной или нескольких строк. Каждому встроенному символу <newline> в тексте должен предшествовать <backslash>. Другие символы <backslash> в тексте должны быть удалены, а следующий символ должен восприниматься буквально.

и если вы прокрутите вниз подОБОСНОВАНИЕон говорит

Требования к принятию символов <blank> и <space> в командных строках были сделаны более явными, чем в ранних предложениях, чтобы четко описать историческую практику и устранить путаницу с фразой «защитить начальные пробелы [sic] и табуляции от удаления, которое выполняется в каждой строке скрипта», которая появляется во многих исторических документах описания утилиты sed текста. (Известно, что не все реализации удаляли символы <blank> из текстовых строк, хотя все они допускали начальные символы <blank> перед адресом в командной строке.)

Так как часть с"обратные косые черты могут быть использованы для"не была включена в эту цитату, оставшаяся фраза«защитить начальные пробелы...»не имеет никакого смысла... 1


В любом случае, подведем итог: некоторые реализации удаляли (а некоторые и сейчас удаляют) пробелы из текстовых строк. Однако, поскольку спецификация POSIX, которой должны соответствовать все реализации, гласит:

Другие символы <обратной косой черты> в тексте должны быть удалены, а следующий за ними символ должен восприниматься буквально.

мы можем сделать вывод, что переносимый способ сделать отступ строк в тексте, который будет вставлен, — это экранировать начальный пробел в каждой из этих строк.


1: Я также не понимаю, почему OSXлюди BSDизменили целый абзац на manстранице, не изменив исходный код — поведение осталось прежним, но раздела man, в котором все это документируется, больше нет.

решение2

Это sedрасширение OSX, а не стандартное поведение. Вы можете увидетьэта ссылка, в функции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, i, c, поведение более странное. В моем FreeBSD 9.3:

$ 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

Куонглмдал лучший ответ, но для протокола вот чтоГНУ sedделает:

echo foo | sed 'i\
     This line starts with spaces.'

Выход:

     This line starts with spaces.
foo

Связанный контент