В руководстве sed говорится о команде N:
Н
Добавьте новую строку в пространство шаблонов, затем добавьте следующую строку ввода в пространство шаблонов. Если ввода больше нет, sed завершает работу, не обрабатывая больше команд.
Теперь, насколько я знаю, sed читает каждую строку ввода, применяет к ней скрипт(ы) и (если -n не указан) печатает ее как выходной поток.
Итак, учитывая следующий пример файла:
Apple
Banana
Grapes
Melon
Выполнение этого:
$ sed '/Banana/N;p'
Насколько я понимаю, sed должен обрабатывать каждую строку ввода: яблоко, банан, виноград и дыня. Итак, я думаю, что вывод будет:
Apple
Apple
Banana
Grapes # since it read the next line with N
Banana
Grapes
Grapes (!)
Grapes (!)
Melon
Melon
Объяснение:
Apple
читается в пространство шаблонов. оно не соответствует регулярному выражению Banana
, поэтому применяется только p
. Он печатается дважды: один раз для команды p
и один раз, потому что sed по умолчанию печатает пространство шаблонов.
Затем Banana
считывается в пространство шаблонов. Он соответствует регулярному выражению, поэтому применяется команда N: поэтому она считывает следующую строку Grapes
в пространство шаблонов, а затем p
печатает ее: Banana\nGrapes
. Затем пространство шаблона печатается снова из-за поведения по умолчанию.
Теперь я ожидаю, что Grapes
будет прочитан в пространство шаблонов, так что Grapes
будет напечатано дважды, так же, как для Apple и Melon.
Но на деле получаю вот что:
Apple
Apple
Banana
Grapes
Banana
Grapes
Melon
Melon
Похоже, что после того, как Grapes
было прочитано как часть команды N, которая была применена к Banana
, оно больше не будет читаться как отдельная строка.
Это так? и если да, то почему это не подчеркивается в документах?
Чтобы отладить это, я добавил =
в ваш скрипт, чтобы вы могли видеть, что генерируется на каждой итерации. Номера строк удобно разграничивают вывод каждой из них. Затем, чтобы определить действие печати по умолчанию в конце каждой итерации, я добавил s/.*/==&==/
, чтобы вы могли видеть, что было напечатано sed
, потому что вы не указали -n
.
sed '/Banana/N;=;p;=;s/.*/==&==/' <<\:
> Apple
> Banana
> Grapes
> Melon
> :
1
Apple
1
==Apple==
3
Banana
Grapes
3
==Banana
Grapes==
4
Melon
4
==Melon==
Таким образом, пространство шаблона, содержащее Banana
и Grapes
, было напечатано дважды, а первая и последняя строки были напечатаны дважды изолированно.
Не уверен, что ваше объяснение верно. Из информации GNU sed
: если не используются специальные команды (например, «D»), пространство шаблонов удаляется между двумя циклами. Итак, насколько я понимаю алгоритм sed, действие N
больше не выполняется. Пространство шаблона Banana\nGrapes
печатается дважды, и следующий цикл начинается с пустого пространства шаблона. Поскольку Grapes
уже прочитано, следующая строка — Melon
, причина, по которой Grapes
печатается не 4 раза, как ожидает OP, а только 2. Обратите внимание, что это объяснение также соответствует вашему выводу с =
.
@RenaudPacalet Спасибо за подсказку; вы были абсолютно правы - обновил ответ. Я придумал лучшую отладку, которая точно показывает, что происходит.
Это может объяснить это (GNU sed):
sed '/Banana/N;p' file --d
SED PROGRAM:
/Banana/ N
p
INPUT: 'file' line 1
PATTERN: Apple
COMMAND: /Banana/ N
COMMAND: p
Apple
END-OF-CYCLE:
Apple
INPUT: 'file' line 2
PATTERN: Banana
COMMAND: /Banana/ N
PATTERN: Banana\nGrapes
COMMAND: p
Banana
Grapes
END-OF-CYCLE:
Banana
Grapes
INPUT: 'file' line 4
PATTERN: Melon
COMMAND: /Banana/ N
COMMAND: p
Melon
END-OF-CYCLE:
Melon
Где --d
- это сокращение от --debug
Вы увидите, как строки INPUT:
переходят в 1,2,4
, потому что второй цикл также захватывает строку ввода 3 с помощью команды N
.
sed
читает каждую запись только один раз. Итак, после того, какGrapes
прочитана командойN
, следующая запись снова неGrapes
, аMelon
.