Я согласен с вами - это , вероятно , является общая проблема. У некоторых общих утилит есть некоторые средства для обработки этого, все же.
nl
nl
, Например, разделяет входной сигнал в логические страницы , как -d
elimited на два символа секции разделителя . Три вхождения в одной строке указывают начало заголовка , два тела и один нижний колонтитул . Он заменяет любой из них, найденных на входе, пустой строкой на выходе - это единственные пустые строки, которые он печатает
Я изменил ваш пример, включив в него другой раздел и вставив его ./infile
. Так это выглядит так:
line A
line B
@@inline-code-start
line X
line Y
line Z
@@inline-code-end
line C
line D
@@start
line M
line N
line O
@@end
Затем я запустил следующее:
sed 's/^@@.*start$/@@@@@@/
s/^@@.*end$/@@/' <infile |
nl -d@@ -ha -bn -w1
nl
можно сказать, чтобы накапливать состояние по логическим страницам, но это не по умолчанию. Вместо этого он будет нумеровать строки своего ввода в соответствии со стилями и секциями . Так -ha
означает номер всех строк заголовка и -bn
означает отсутствие строк тела - как это начинается в теле .
До тех пор, пока я не узнал об этом, я использовал nl
для любого ввода, но после осознания того, что это nl
может исказить вывод в соответствии с его -d
ограничителем по умолчанию, \:
я научился быть с ним более осторожным и grep -nF ''
вместо этого начал использовать для непроверенного ввода. Но еще один урок, извлеченный в тот день, заключался в том, что он nl
может быть очень полезен в других отношениях - например, в этом - если вы просто немного измените его входные данные - как я делаю sed
выше.
ВЫХОД
line A
line B
1 line X
2 line Y
3 line Z
line C
line D
1 line M
2 line N
3 line O
Вот еще немного о том nl
, замечаете ли вы выше, как все строки, кроме пронумерованных, начинаются с пробелов? когдаnl
номера строк, он вставляет определенное количество символов в голову каждого. Для этих строк он не -w
нумеруется - даже пробелы - он всегда соответствует отступу, вставляя ( idth count + -s
eparator len) * пробелы в начале ненумерованных строк. Это позволяет точно воспроизводить ненумерованный контент, сравнивая его с пронумерованным контентом - и при этом не прилагая особых усилий. Если вы считаете, что nl
это разделит его входные данные на логические разделы, и что вы можете вставить произвольные -s
трэны в начало каждой строки, которую он нумерует, тогда становится довольно легко обработать его вывод:
sed 's/^@@.*start$/@@@@@@/
s/^@@.*end/@@/; t
s/^\(@@\)\{1,3\}$/& /' <infile |
nl -d@@ -ha -bn -s' do something with the next line!
'
Вышеуказанные отпечатки ...
line A
line B
1 do something with the next line!
line X
2 do something with the next line!
line Y
3 do something with the next line!
line Z
line C
line D
1 do something with the next line!
line M
2 do something with the next line!
line N
3 do something with the next line!
line O
GNU sed
Если nl
это не ваше целевое приложение, тогда GNUsed
может e
выполнить для вас произвольную команду оболочки в зависимости от соответствия.
sed '/^@@.*start$/!b
s//nl <<\\@@/;:l;N
s/\(\n@@\)[^\n]*end$/\1/
Tl;e' <infile
Выше sed
вводятся входные данные в пространстве шаблонов, пока их не будет достаточно, чтобы успешно пройти замену T
est и прекратить b
ранчо обратно к :l
абелю. Когда это произойдет, этоe
выполняет nl
ввод, представленный <<
здесь как документ для всего остального пространства шаблонов.
Рабочий процесс выглядит так:
/^@@.*start$/!b
- если
^
вся линия $
никак !
не /
соответствует /
указанной выше модели, то она b
разводят из сценария и autoprinted - так что с этого момента мы работаем только с серией линий , которая началась с рисунком.
s//nl <<\\@@/
- пустое
s//
поле /
соответствует последнему адресу, который sed
пытался найти соответствие, поэтому вместо него эта команда заменяет всю @@.*start
строку nl <<\\@@
.
:l;N
- Команда
:
определяет метку ветки - здесь я установил один с именем :l
abel. Команда N
ext добавляет следующую строку ввода к \n
пробелу шаблона, за которой следует символ ewline. Это один из немногих способов получить \n
ewline в sed
пространстве паттернов - \n
персонаж ewline является верным разделителем для sed
дер, который делал это некоторое время.
s/\(\n@@\)[^\n]*end$/\1/
- эта
s///
операция может быть успешной только после того, как встречается начало, и только в первом последующем появлении конечной строки. Он будет действовать только на пространство паттернов, в котором \n
сразу же за конечной ewline будет отмечен @@.*end
самый конец $
паттерна. Когда он действует, он заменяет всю совпавшую строку \1
первой \(
группой \)
или \n@@
.
Tl
- то
T
команда Текущей ветви к метке (если имеется) , если успешная замена не произошла с момента последнего ввод линия затащила шаблон (как и я ш / N
) . Это означает, что каждый раз, когда \n
ewline добавляется в пространство шаблонов, которое не соответствует вашему конечному разделителю, команда T
est завершается неудачно и возвращается к :l
abel, что приводит к sed
вытягиванию N
строки ext и повторению цикла до успешного завершения .
e
Когда замена для конечного матча успешно и сценарий не филиальную назад для неисправного T
ЭСТА, sed
будет e
xecute команды , которая l
ooks , как это:
nl <<\\@@\nline X\nline Y\nline Z\n@@$
Вы можете убедиться в этом сами, отредактировав последнюю строку там, чтобы она выглядела так Tl;l;e
.
Это печатает:
line A
line B
1 line X
2 line Y
3 line Z
line C
line D
1 line M
2 line N
3 line O
while ... read
Последний способ сделать это, и, возможно, самый простой, - это использовать while read
цикл, но не без причины. Оболочка - (особенно bash
оболочка) - обычно ужасна при обработке ввода в больших количествах или в устойчивых потоках. Это также имеет смысл - работа оболочки заключается в том, чтобы обрабатывать ввод за символом и вызывать другие команды, которые могут обрабатывать больше.
Но важно то, что его роль заключается в том, что оболочка не должна read
перегружать ввод - она указана для того, чтобы не буферизовать ввод или вывод до такой степени, что она потребляет так много или недостаточно ретранслирует во времени, чтобы не вызывать недостающие команды, которые она вызывает - к байту. Так read
что это отличный тест ввода - для получения return
информации о том, остался ли ввод, и вам нужно вызвать следующую команду, чтобы прочитать его, но в целом это не лучший способ.
Однако вот пример того, как можно использовать read
и другие команды для обработки ввода синхронно:
while IFS= read -r line &&
case $line in (@@*start) :;; (*)
printf %s\\n "$line"
sed -un "/^@@.*start$/q;p";;
esac;do sed -un "/^@@.*end$/q;=;p" |
paste -d: - -
done <infile
Первое, что происходит для каждой итерации, - это read
вытягивание строки. Если он успешен, это означает, что цикл еще не достиг EOF, и, таким образом, case
он соответствует начальному разделителю, и do
блок немедленно выполняется. Остальное printf
печатает $line
оноread
и sed
называется.
sed
будет p
набирать каждую строку, пока не встретит начальный маркер - когда он q
полностью использует ввод. Переключатель -u
nbuffered необходим для GNU, sed
потому что он может жадно буферизовать в противном случае, но - согласно спецификации - другой POSIXsed
должны работать без какого-либо специального рассмотрения - при условии, что <infile
это обычный файл.
При первом sed
q
использовании оболочка выполняет do
блок цикла, который вызывает другой, sed
который печатает каждую строку, пока не встретит маркер конца . Он передает свой вывод paste
, потому что он печатает номера строк, каждый на своей строке. Как это:
1
line M
2
line N
3
line O
paste
затем вставляет их вместе в :
символы, и весь вывод выглядит так:
line A
line B
1:line X
2:line Y
3:line Z
line C
line D
1:line M
2:line N
3:line O
Это всего лишь примеры - все может быть сделано здесь либо в тесте, либо в блоках do, но первая утилита не должна потреблять слишком много входных данных.
Все задействованные утилиты читают один и тот же ввод - и печатают свои результаты - каждая по-своему. Такого рода вещи могут быть трудно получить навык - потому что различные утилиты будут помещать в буфер больше , чем другие , - но вы можете вообще полагаться на dd
, head
и sed
делать правильные вещи (хотя, для GNU sed
, вам нужно CLI-переключатель) и Вы всегда должны быть в состоянии положиться, read
потому что это, по своей природе, очень медленно . И именно поэтому вышеуказанный цикл вызывает его только один раз на входной блок.
nl
не должен накапливать государство . Посмотритеnl -d
и проверьтеman
/info
страницы для получения информации оnl
«S разделе разделителем .