щодо портативного sed -e… db або! б?


12

У цьому редагувати Stéphane Chazelas POSIXifies (знову) моє sedформатування, вставляючи -eрозрив XPression і інший -eXPression заяву. Тепер, я можу просто запитати його, чому в коментарях, я думаю, але це вже редакція №18 щодо цієї відповіді, і майже всі попередні вже були завдяки подібним халявам (якщо ви можете побачити видалені коментарі, ви знаєте, що Я маю на увазі) . Крім того, я думаю, що я досить близький, щоб зрозуміти, чому формулювати це таким чином, що може бути кориснішим. Тож ось сподіваємось ...

Я, як правило, вважаю за краще зберігати загальну кількість sed -expressions до однієї, якщо я можу, але я також більше віддаю перевагу відповідності специфікації якомога ближче, особливо коли різниця становить не більше ніж a <space>та an -e. Але я не можу цього зробити, якщо не розумію, чому я повинен. Ось короткий опис сучасного стану мого розуміння:

  • ' -e 'перерва може стерпний стояти протягом sedсценарію \nперерви ewline в sedкомандному рядку заяві ... Я правда нечіткий про те, чому

  • завершувальній дузі у sed {функції }має передувати \nперерва ewline, як зазначено тут:

    • Перед цим символом <right-brace>передує знак "a" <newline>та може передувати або слідувати <blank>символам.
  • \nперерву ewline аналогічно потрібно після будь-якого використання ... a, b, c, i, r, t, w, або :.

Але я не розумію чітко, як визначення {функції }стосується !не оператора. Єдина згадка, яку я знаходжу про оператора заперечення у специфікаціях:

  • Функції може передувати один або більше !символів, і в цьому випадку функція повинна застосовуватися, якщо адреси не вибирають простір шаблону.

Чи означає це , що використання !має на увазі {брекети }? Що з $!команд - їх також слід розділяти ' -e 'перервами? Чи було саме це питання, коли Stéphane останнім часом POSIXIFіфікував мою відповідь?

Я думаю, що це або !оператор заперечення, або це bзаява про ранчо, до якого він звертається у своїй редакції - або, можливо, це обидва одразу - але я не знаю і мені це хотілося б. Якщо це лишеb твердження про ранчо, то, я вважаю, що це dзробить замість цього і усуне необхідність ' -e 'перерви, але я вважаю за краще бути впевненим, перш ніж загрожувати трикратною відповіді POSIXified . Ви можете допомогти?

Я ризикну все - таки , а не з якоюсь - або великою часткою впевненості ...


З b;n;:b, ви розгалужуєтесь до мітки, яка називається ";n;:b"в історичних та POSIX-сегментах (і GNU sed не з цього приводу).
Стефан Шазелас

@ StéphaneChazelas - Я розумію, що :ти їхав додому місяці тому. Але я не повністю розумію, чому друга sedкоманда була аналогічно POSIXified .
mikeserv

1
У будь-якому випадку, специфікація POSIX для sedмене дуже незрозуміла. У минулому я кілька разів просив роз'яснення, але не думаю, що це було оновлено. Хороший тест - спробувати з інструментальним інструментом heirloom (Solaris one, отриманий з оригіналу і на якому в основному базується специфіка POSIX).
Стефан Шазелас

1
@syntaxerror - я не вірю, що це взагалі так. якщо ви прочитаєте специфікацію, то виявите, що s///заборонені дії повинні приймати ланцюжок з a ; . він розмивається навколо команд, які повинні бути розмежовані новим рядком, і як це -eможе бути в цьому випадку - принаймні, це для мене. ive все ще наткнутися на sedщо doesnt інтерпретувати їх досить взаємозамінно, хоча.
mikeserv

1
@syntaxerror - Мені це подобається, але ви повинні знати, що вам не потрібен ;попередній рядок - новий рядок чудово. Чесно кажучи, ви могли б обійтися без -eцілісних повністю і просто написати файл, як #!/bin/sedпри кожній команді в новому рядку - або ті, для яких не потрібні такі роздільники, а не обмежені ;. Ті , які роблять вимагають перекладу рядка , як правило , є ті , які приймають довільні вхідні - :імена міток і команди , які відносяться до них , як bі tчи закривати }Curlies для функцій, або rEAD та wобряду , які приймають ім'я файлу арг. Всі вони переносимо, за якими слід дотримуватися \n.
мікесерв

Відповіді:


4

Тож давно на це запитання була відповідь, і, хоча я врешті інтуїтивно розробив, як це зробити правильно, майже в кожному випадку, деякий час тому, я лише нещодавно зумів досить конкретно розуміти текст із стандарту. . Це насправді там сказано досить просто - я, мабуть, просто нерозумно його переглядав.

Усі відповідні частини тексту містяться під заголовком ...

  • Редагування команд уsed :

    • Аргумент текст повинен складатися з однієї або декількох рядків. Кожному вкладеному \nрядку тексту в тексті передує \зворотний нахил . Інші штрихи в тексті повинні бути видалені, а наступні символи мають бути досліджені буквально.

    • В rі wкомандних дієсловах, і wпрапор в sкоманду, візьміть додатковий ОФАЙЛ (або wfile ) параметр, відокремлений від команди дієслова букви або прапора однієї або більше <blank>s; реалізації можуть дозволити розділення нуля як розширення.

    • Команда дієслів, крім {, a, b, c, i, r, t, w, :, і #може супроводжуватися ;точкою з коми, опціонально <blank>s, і іншої команди дієслова. Однак, коли sдієслово команд використовується із wпрапором, слідування за ним за допомогою іншої команди таким чином дає невизначені результати.

... в ...

  • Опції: Можна вказати кілька -eта -fпараметри. Усі команди додаються до сценарію у визначеному порядку, незалежно від їх походження.

    • -e скрипт - Додайте команди редагування, визначені параметром-параметром сценарію, до кінця сценарію редагування команд. Сценарій варіант аргументів, має ті ж властивості, що і сценарій операнда, описаний в операнди розділі.

    • -f script_file - Додайте команди редагування у файл script_file до кінця сценарію.

І останнє в ...

  • Операнди:

    • script - рядок, який використовується як сценарій редагування команд. У заяві не має бути скрипту, який порушує обмеження текстового файлу, за винятком того, що кінцевим символом не повинно бути \newline.

Отже, коли ви приймаєте його цілком, має сенс, що будь-яка команда, за якою необов'язково слідує довільний параметр без заздалегідь визначеного роздільника (на відміну від, s d sub d repl d flagнаприклад,), повинна розмежовуватися на \nнерозглянутій лінії виходу.

Можна стверджувати, що значення ; є заздалегідь визначеним роздільником, але в цьому випадку використання команди ;для будь-якої з [aic]команд вимагає включення в реалізацію окремого аналізатора спеціально для цих трьох команд - окремої, тобто від аналізатора, який використовується [:brw], наприклад. Інакше впровадження потребує того, щоб ; також не було зворотної косої риски в текстовому параметрі, і вона з цього моменту лише ускладнюється.

Якби я писав текст, sedякий хотів би бути сумісним і ефективним, я би не писав такого окремого аналізатора, я очікую - за винятком того, що, можливо, [aic]має \nвиникнути помилка синтаксису, якщо за ним не одразу піде ewline. Але це проста проблема токенізації - справа в розмежувачі кінців, як правило, є більш проблематичною. Я б просто так написав:

sed -e w\ file\\ -e one -e '...;and more commands'

... і ...

sed -e a\\ -e appended\\ -e text -e '...;and more commands'

... поводився б дуже подібним чином, коли перший створив би і записав у файл з назвою:

file
one

... а другий додав би блок тексту до поточного рядка на виході, як ...

appended
text

... тому що обидва поділяють один і той же код розбору для параметра.

А щодо питання { ... }і $!питання - ну, я був там далеко. Однією командою, якій передує адреса, є не функція, а скоріше це лише адресована команда. Практично всі команди, включаючи { визначення функції } , вказані для прийняття /one/чи /one/,/two/адреси - за винятком визначення #коментарів та :міток . І адреса може бути номером рядка або звичайним виразом, і її можна заперечувати !. Отже всі ...

$!d
/address/s/ub/stitution/
5!y/d/c/

... можуть супроводжуватися ;командами a і більше відповідно до стандарту, але якщо для однієї адреси потрібно більше команд, і ця адреса не повинна переоцінюватися після виконання кожної команди, тоді слід використовувати {функцію }типу:

/address/{ s//replace addressed pattern/
           s/do other conditional/substitutions/
           s/in the same context/without/
           s/reevaluating/address/
}

... де {не може слідувати на одній і тій же лінії шляхом закриття, }і закриття }не може відбуватися, крім випадків на початку рядка. Але якщо міститься команда не повинна інакше дотримуватися \newline, вона також не повинна бути функцією. Таким чином, всі вищезазначені s///вставки - і навіть }фіксатор, що перебуває у фіксації, можуть переноситися ;крапками з комою та подальшими командами.

Я продовжую говорити про \nобмежувачі ewline, але натомість питання -eстосується тверджень xpression. Але два - це одне і те саме, і ключовим співвідношенням є те, що скрипт може бути або буквальним аргументом командного рядка, або файлом з будь-яким із них -[ef], і що обидва інтерпретуються як текстові файли (вказані для завершення в \newline) , але ні необхідність фактично закінчується в \newline. До цього я можу reasonbly (я сподіваюся) , роблять висновок , що \0NULрозмежовані аргумент має на увазі закінчення \newline, і , як всі аргументи Заклику отримати принаймні) на \0NULроздільник в будь-якому випадку, то або має працювати нормально.

Насправді, на практиці, у будь-якому випадку, окрім випадків, коли стандарт визначає \зворотну косу рису, слід винести новий рядок, який я переносно знайшов ...

sed -e ... -e '...\' -e '...'

... працювати так само добре. І в будь-якому випадку - знову ж таки, на практиці - там, де \nпотрібно вимагати не втеченого еуліну ...

sed -e '...' -e '...'

... працював і на мене. Єдиний виняток, про який я згадую вище, це ...

sed -e 's/.../...\' -e '.../'

... що не працює для жодної реалізації в жодному з моїх тестів. Я цілком впевнений, що це повертається до вимоги до текстового файлу та до факту, що s/// постачається з роздільником, і тому немає жодної причини, щоб одне твердження повинно охоплювати \0NULобмежені аргументи.

Отже, на закінчення, ось короткий перенос портативних способів написання кількох видів sedкоманд:

Для будь-якого з [aic]:

...commands;[aic]\
text embedded newline\
delimiting newline
...more;commands...

... або ...

sed -e '...commands;[aic]\' -e 'text embedded newline\' -e 'delimiting newline' -e '.;.;.'

Для будь-якого з випадків, [:rwtb]коли параметр є необов’язковим (для всіх, окрім :), але \nобмежувальний рядок не є . Зверніть увагу , що я ніколи не була причина , щоб спробувати кілька лінії міток параметрів , як буде використовуватися [:tb], але writing / reading на кілька рядків в [RW] файлу параметрів зазвичай приймається без питань по sedх я випробував до тих пір , як вбудований \newline ухиляється з \нахилом. Проте стандарт не вказує безпосередньо, що параметри мітки та файлу [rw] повинні бути розібрані однаково до текстуПараметри і не згадує \newlines щодо перших двох, за винятком того, як вони розмежовують їх.

...commands;[:trwb] parameter
...more;commands...

... або ...

sed -e '[:trwb] parameter' -e '...'

... де зазначене <space>вище не є обов'язковим [:tb].

І останнє ...

...;address[!]{ ...function;commands...
};...more;commands....

... або ...

sed -e '...;address[!]{ ...function;commands...' -e '};...more;commands...'

... де будь-який із зазначених вище команд (виключаючи :) також приймає щонайменше один адресу , і який може бути або /регулярним виразом /або номер рядка і може бути зведений на немає з !, але , якщо більш ніж одна команди необхідна для однієї оцінки адреси , то Необхідно використовувати {контекстний }діапазон, що розмежовує контекст . Функція може містити навіть декілька \nкоманд, обмежених ewline, але кожна повинна бути обмежена в дужках, як це було б інакше.

І ось як писати портативні sedсценарії.


2
Чому ви не приймаєте власну відповідь?
Філіппос
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.