Я был под впечатлением отСпецификации 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
Нет, но ваш скрипт будет переносимым, пока вы экранируете любой начальный пробел. Почему? Потому что некоторые sed
s удаляют пустые символы из текстовых строк, и единственный способ избежать этого — экранировать начальный пробел, как объясняют эти страницы руководства, датируемые прошлым веком: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