Я погодився б із вами - це, мабуть , загальна проблема. Деякі загальні утиліти мають деякі можливості для роботи з ним.
nl
nl, наприклад, розділяє вхід на логічні сторінки, як -dусунуто роздільником двох розділів . Три події в рядку самі по собі вказують на початок заголовка , два тіла і один колонтитул . Він замінює будь-який з цих даних, що знаходяться на вході, порожнім рядком на виході - що це єдині порожні рядки, які він коли-небудь друкує
Я змінив ваш приклад, щоб включити ще один розділ і вкласти його ./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 + -separator 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це не ваша цільова програма, то GNU sedможе eвиконувати довільну команду оболонки для вас залежно від відповідності.
sed '/^@@.*start$/!b
s//nl <<\\@@/;:l;N
s/\(\n@@\)[^\n]*end$/\1/
Tl;e' <infile
Вище sedзбирає вхід у простір шаблону, поки його не вистачить для успішного проходження заміщення Tі перестаньте bрухатися назад до :lабеля. Коли він це робить, він eвиконує nlз введенням, представленим як <<тут-документ, для всіх решти його простору шаблонів.
Робочий процес такий:
/^@@.*start$/!b
- якщо
^вся лінія $ніяк !НЕ /відповідає /зазначеній вище моделі, то вона bрозводять з сценарію і autoprinted - так що з цього моменту ми працюємо тільки з серією ліній , яка почалася з малюнком.
s//nl <<\\@@/
- порожнє
s//поле /стоїть за останньою адресою, яка sedнамагалася відповідати, тому ця команда заміщає весь @@.*startрядок nl <<\\@@замість цього.
:l;N
:Команда визначає мітку філії - тут я поставив один з ім'ям :lАвеля. Команда Next додає наступний рядок вводу до простору візерунка з подальшим \nсимволом ewline. Це один з небагатьох способів отримати \nеуліну в sedпросторі візерунка - \nперсонаж ewline - це справжній роздільник для sedдер, який це робив вже деякий час.
s/\(\n@@\)[^\n]*end$/\1/
- це
s///встановлення може бути успішним лише після початку запуску і лише при першому наступному появі кінцевої лінії. Він буде діяти лише на просторі шаблону, в якому за кінцевою \nлініями одразу слідує @@.*endмаркування самого кінця $простору візерунка. Коли він дійде, він замінює весь збігається рядок \1першою \(групою \), або \n@@.
Tl
- команда
Test відгалужується до мітки (якщо вона надана), якщо успішної заміни не відбулося з моменту останнього введення рядка вводу в простір шаблону (як я це роблю w / N) . Це означає, що щоразу, коли \newline додається до простору шаблону, який не відповідає вашому кінцевому розмежувачу, команда Test не вдається і відхиляється назад до :lабелі, що призводить до sedвитягування Nрядка ext і циклічного циклу, поки не буде успішним.
e
Коли заміна для кінцевого матчу успішно і сценарій не філіальну назад для несправного TЕСТА, sedбуде execute команди , яка looks , як це:
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повністю не використовує введення. -uNbuffered вимикач необхідний для GNU , sedоскільки він може буфер , а жадібність інакше, але - в відповідності зі специфікацією - інший POSIX seds повинен працювати без будь - якого спеціального розгляду - до тих пір , як <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
Це лише приклади - тут можна зробити все, що завгодно, або в тесті, або в блоках, але перша утиліта не повинна використовувати занадто багато вкладних даних.
Усі зацікавлені утиліти читають один і той же вхід - і друкують їх результати - кожен по-своєму. Такого роду речі можуть бути важко отримати навик - тому що різні утиліти будуть поміщати в буфер більше , ніж інші , - але ви можете взагалі покладатися на dd, headі sedробити правильні речі (хоча, для GNU sed, вам потрібно CLI-перемикач) і ви завжди повинні мати можливість покладатися на це read- адже це, за своєю природою, дуже повільно . І тому вищевказаний цикл називає його лише один раз на вхідний блок.
nlне має накопичувати стан . Подивітьсяnl -dі перевіртеman/infoсторінки для отримання інформації проnl«S розділі роздільником .