что касается портативного сед-е ... дБ или! б?

12

В этом редактировании Stéphane Chazelas POSIX исправляет (снова) мое sedформатирование, вставляя -eразрыв xpression и еще -eодин оператор xpression. Теперь, я мог бы просто спросить его, почему в комментариях, я полагаю, но это уже редакция № 18 для этого ответа, и почти все предыдущие были уже благодаря подобной халяве (если вы видите удаленные комментарии, вы будете знать, что Я имею в виду) . Кроме того, я думаю, что я достаточно близок к пониманию того, почему формулировать это так, чтобы это могло быть более полезным в целом. Так что надеемся ...

Как правило, я предпочитаю, чтобы мои общие sed -eвыражения были равны единице, но я бы также предпочел соответствовать спецификации настолько близко, насколько я могу, особенно когда разница составляет не более чем a <space>и an -e. Но я не могу сделать это, если я не понимаю, почему я должен. Вот краткое изложение текущего состояния моего понимания:

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

  • закрывающей скобке в sed {функции }должен предшествовать \nразрыв строки, как указано здесь:

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

Но я не совсем понимаю, как определение {функции }относится к !неоператору. Единственное упоминание об операторе отрицания, которое я нахожу в спецификации:

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

Значит ли это, что использование скобок !подразумевает ? Что из команд - они также должны быть разделены перерывами? Было ли это то, что было решено, когда Стефан в последний раз POSIXified мой ответ?{}$!' -e '

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

Я рискну все - таки , а не с какой - либо большой долей уверенности ...

mikeserv
источник
С помощью b;n;:bэтого вы ";n;:b"переходите на метку, называемую в исторических и POSIX-сборках (и GNU sed не в этом отношении).
Стефан Шазелас
@ StéphaneChazelas - я получу :роль - ты поехал домой несколько месяцев назад. Но я не совсем понимаю, почему вторая sedкоманда была так же POSIXified .
mikeserv
1
В любом случае, спецификация POSIX для sedменя очень неясна. Я просил разъяснения несколько раз в прошлом, но я не думаю, что это было обновлено в результате. Хорошим тестом является попытка использования инструментальной панели семейной реликвии (Solaris, взятой из оригинала и на которой в значительной степени основана спецификация POSIX).
Стефан Шазелас
1
@syntaxerror - я не верю, что это так. если вы прочтете спецификацию, вы обнаружите, что s///учреждения должны принимать цепочку с ; , оно расплывчато вокруг команд, которые должны быть разделены новой строкой, и как они -eмогут стоять в этом случае - по крайней мере, для меня. Я еще не наткнулся на, sedкоторый не интерпретирует их довольно взаимозаменяемо, хотя.
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 script - добавить команды редактирования, заданные параметром-аргументом script, в конец скрипта команд редактирования. Сценарий вариант аргументов, имеет те же свойства, что и сценарий операнда, описанный в операнды разделе.

    • -f script_file - добавить команды редактирования в файле script_file в конец скрипта.

И последний в ...

  • Операнды:

    • script - строка, используемая в качестве сценария редактирования команд. Приложение не должно представлять сценарий, который нарушает ограничения текстового файла, за исключением того, что последний символ не обязательно должен быть в виде \nстроки.

Таким образом, когда вы берете его полностью, имеет смысл, что любая команда, за которой необязательно следует произвольный параметр без предопределенного разделителя (в отличие, 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/

... может сопровождаться ;несколькими командами в соответствии со стандартом, но если для одного адреса требуется больше команд, и этот адрес не следует переоценивать после выполнения каждой команды, то должна использоваться {функция }, подобная следующей:

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

... где {за этой же строкой не может следовать закрытие }и что закрытие }не может произойти, кроме как в начале строки. Но если в противном случае за содержащейся командой не должна следовать электронная \nлиния, то она также не должна быть включена в функцию. Таким образом, за всеми перечисленными выше 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]где параметр является необязательным (для всех, кроме :), но \newline разграничения не является . Обратите внимание, что у меня никогда не было причины пробовать использовать несколько параметров меток строк, как это было бы с ними [:tb], но что wпереход / rчтение нескольких строк в параметрах файла [rw] обычно принимается без вопросов seds, которые я тестировал, пока встроенный \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скрипты.

mikeserv
источник
2
Почему ты не принимаешь свой ответ?
Филиппос