Я погодився б із вами - це, мабуть , загальна проблема. Деякі загальні утиліти мають деякі можливості для роботи з ним.
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 + -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
це не ваша цільова програма, то 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
Авеля. Команда N
ext додає наступний рядок вводу до простору візерунка з подальшим \n
символом ewline. Це один з небагатьох способів отримати \n
еуліну в sed
просторі візерунка - \n
персонаж ewline - це справжній роздільник для sed
дер, який це робив вже деякий час.
s/\(\n@@\)[^\n]*end$/\1/
- це
s///
встановлення може бути успішним лише після початку запуску і лише при першому наступному появі кінцевої лінії. Він буде діяти лише на просторі шаблону, в якому за кінцевою \n
лініями одразу слідує @@.*end
маркування самого кінця $
простору візерунка. Коли він дійде, він замінює весь збігається рядок \1
першою \(
групою \)
, або \n@@
.
Tl
- команда
T
est відгалужується до мітки (якщо вона надана), якщо успішної заміни не відбулося з моменту останнього введення рядка вводу в простір шаблону (як я це роблю w / N
) . Це означає, що щоразу, коли \n
ewline додається до простору шаблону, який не відповідає вашому кінцевому розмежувачу, команда T
est не вдається і відхиляється назад до :l
абелі, що призводить до 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
оскільки він може буфер , а жадібність інакше, але - в відповідності зі специфікацією - інший POSIX sed
s повинен працювати без будь - якого спеціального розгляду - до тих пір , як <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 розділі роздільником .