Поиск…


Вступление

Чтобы процитировать сообщение с @ SnoringFrog по созданию темы:

«Одна из самых больших ошибок при использовании sed - это сценарии, которые не работают (или преуспевают неожиданным образом), потому что они были написаны для одного, а не для другого. Простое сокращение более значительных различий было бы хорошим».

замечания

macOS использует версию BSD sed [1] , которая во многом отличается от версии GNU sed , поставляемой с дистрибутивами Linux .

Их общим знаменателем является функциональность, установленная POSIX : см. sed POSIX sed .

Самый портативный подход - использовать только функции POSIX , но, тем не менее, ограничивает функциональность :

  • В частности, POSIX определяет поддержку только для базовых регулярных выражений, которые имеют много ограничений (например, отсутствие поддержки | (чередование) вообще, без прямой поддержки + и ? ) И различных требования вылетающих.

    • Оговорка: GNU sed (без -r ), не поддерживает \| , \+ и \? , который НЕ соответствует POSIX; используйте --posix для отключения (см. ниже).
  • Использовать только функции POSIX :

    • (обе версии): используйте только параметры -n и -e (в частности, не используйте -E или -r чтобы включить поддержку расширенных регулярных выражений)

    • GNU sed : добавьте опцию --posix для обеспечения только функции POSIX (вам это не нужно, но без нее вы можете случайно использовать функции, отличные от POSIX, не заметив, caveat : --posix сам по себе не совместим с POSIX )

    • Использование только функций POSIX означает более жесткие требования к форматированию (из-за многих удобств, доступных в GNU sed ):

      • Такие последовательности символов управления, как \n и \t , обычно НЕ поддерживаются.
      • Команды ярлыков и ветвлений (например, b ) должны сопровождаться фактической новой строкой или продолжением через отдельный параметр -e .
      • Подробнее см. Ниже.

Однако в обеих версиях реализованы расширения для стандарта POSIX:

  • какие расширения, которые они реализуют, различаются (GNU sed реализует больше).
  • даже те расширения, которые они оба реализуют, частично отличаются синтаксисом .

Если вам нужна поддержка платформ BOTH (обсуждение различий):

  • Несовместимые функции:

    • Использование опции -i без аргумента (обновление на месте без резервного копирования) несовместимо:

      • BSD sed : ДОЛЖНО использовать -i ''
      • GNU sed : ДОЛЖНО использовать только -i (равнозначно: -i'' ) - использование -i '' НЕ работает.
    • -i разумно включает строку нумерации строк ввода в GNU sed и последние версии BSD sed (например, на FreeBSD 10), но не имеет значения для macOS с 10.12 .
      Обратите внимание, что в отсутствие -i всех версий число строк кумулятивно отображается во входных файлах.

    • Если последняя строка ввода не имеет завершающей новой строки (и печатается):

      • BSD sed : всегда добавляет новую строку на выходе, даже если строка ввода не заканчивается на один.
      • GNU sed : сохраняет статус конечной новой строки , т. Е. Добавляет новую строку только в том случае, если строка ввода заканчивается на одном.
  • Общие характеристики:

    • Если вы ограничите свои сценарии sed тем, что поддерживает BSD sed , они, как правило, будут работать и в GNU sed - с заметным исключением использования расширенных функций регулярного выражения, связанных с платформой, с -E . Очевидно, вы также откажетесь от расширений, характерных для версии GNU. См. Следующий раздел.

Рекомендации по кросс-платформенной поддержке (OS X / BSD, Linux), обусловленные более строгими требованиями версии BSD :

Обратите внимание, что сокращенные macOS и Linux иногда используются ниже, чтобы ссылаться на версии sed и BSD соответственно, потому что они являются версиями акций на каждой платформе. Тем не менее, можно установить GNU sed на macOS, например, используя Homebrew с brew install gnu-sed .

Примечание . За исключением случаев использования флагов -r и -E ( расширенные регулярные выражения), приведенные ниже инструкции относятся к написанию сценариев sed совместимых с POSIX .

  • Для соответствия POSIX вы должны ограничить себя POSIX BREs ( базовые регулярные выражения) , которые, к сожалению, как следует из названия, являются довольно базовыми.
    Предостережение : не предполагайте, что \| , \+ и \? поддерживаются: хотя GNU sed поддерживает их (если используется --posix ), BSD sed не выполняет - эти функции не совместимы с POSIX.
    В то время как \+ и \? могут быть эмулированы в соответствии с POSIX:
    \{1,\} для \+ ,
    \{0,1\} для \? ,
    \| (чередование) не может, к сожалению.

  • Для более мощных регулярных выражений используйте -E (а не -r ) для поддержки ERE ( расширенные регулярные выражения) (GNU sed не документирует -E , но он работает там как псевдоним -r ; более новая версия BSD sed , например, на FreeBSD 10, теперь также поддерживают -r , но версия MacOS от 10.12 не делает).
    Предостережение . Несмотря на то, что использование -r / -E означает, что ваша команда по определению не совместима с POSIX, вы все равно должны ограничивать себя POSIX ERE (расширенные регулярные выражения) . К сожалению, это означает, что вы не сможете использовать несколько полезных конструкций, в частности:

    • потому что они специфичны для платформы (например, \< на Linux, [[:<]] на OS X).
    • обратные ссылки внутри регулярных выражений (в отличие от «обратных ссылок» на совпадения записей в заменяющей строке вызовов функций s ), поскольку BSD sed не поддерживает их в расширенных регулярных выражениях (но, что любопытно, делает это в базовые , где они предназначены для POSIX).
  • Управляющие символы, такие как \n и \t :

    • В регулярных выражениях (как в шаблонах для выбора линии, так и в первом аргументе функции s ) предположим, что только \n распознается как escape-последовательность (редко используется, поскольку пространство шаблонов обычно представляет собой одну строку (без завершения \n ) но не внутри символьного класса , так что, например, [^\n] не работает; (если ваш вход не содержит управляющих символов, кроме \t , вы можете эмулировать [^\n] с помощью [[:print:][:blank:]] , в противном случае - символы управления соединением в виде литералов [2] ) - обычно включают контрольные символы в виде литералов , либо с помощью связанных строк в ANSI C (например, $'\t' ) в оболочек, поддерживающих его ( bash, ksh, zsh ), или с помощью подстановок команд с помощью printf (например, "$(printf '\t')" ) .

      • Только Linux:
        sed 's/\t/-/' <<<$'a\tb' # -> 'a-b'
      • OSX и Linux:
        sed 's/'$'\t''/-/' <<<$'a\tb' # ANSI C-quoted string
        sed 's/'"$(printf '\t')"'/-/' <<<$'a\tb' # command subst. with printf
    • В строках замещения, используемых с командой s , предположим, что NO управляющих последовательностей escape-символов поддерживается , так что опять же включите контрольные символы. как литералы , как указано выше.

      • Только Linux:
        sed 's/-/\t/' <<<$'ab' # -> 'a<tab>b'
      • macOS и Linux:
        sed 's/-/'$'\t''/' <<<'a-b'
        sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
    • То же самое для текстовых аргументов i и a функции: не использовать последовательности управления символьные - смотри ниже.

  • Ярлыки и ветвление : метки, а также аргумент имени метки для функций b и t должны сопровождаться либо литеральной новой линией, либо сплайсинговым в $'\n' . Кроме того, используйте несколько опций -e и завершайте их сразу после имени метки.

    • Только Linux:
      sed -n '/a/ bLBL; d; :LBL p' <<<$'a\nb' # -> 'a'
    • macOS и Linux:
      • EITHER (фактические строки новой строки):
        sed -n '/a/ bLBL d; :LBL p' <<<$'a\nb'
      • ИЛИ (вложенные экземпляры $\n ):
        sed -n '/a/ bLBL'$'\n''d; :LBL'$'\n''p' <<<$'a\nb'
      • ИЛИ (несколько -e опций):
        sed -n -e '/a/ bLBL' -e 'd; :LBL' -e 'p' <<<$'a\nb'
  • Функции i и a для вставки / добавления текста : следуйте за именем функции по \ , за которым следует либо буквальная новая строка, либо сплайсинг в $'\n' прежде чем указывать текстовый аргумент.

    • Только Linux:
      sed '1 i new first line' <<<$'a\nb' # -> 'new first line<nl>a<nl>b'
    • OSX и Linux:
      sed -e '1 i\'$'\n''new first line' <<<$'a\nb'
    • Замечания:
      • Без -e текстовый аргумент необъяснимо не завершен с использованием новой строки при выводе на macOS (ошибка?).
      • Не используйте escape-символы, такие как \n и \t в текстовом аргументе, поскольку они поддерживаются только в Linux.
      • Если текстовый аргумент имеет фактические внутренние символы новой строки, \ -escape их.
      • Если вы хотите поместить дополнительные команды после текстового аргумента, вы должны закончить его с помощью (неэкспертированной) новой строки (будь то литеральный или сращиваемый) или продолжить с отдельной опцией -e (это общее требование, которое применяется ко всем версиям) ,
  • Внутри списков функций (несколько вызовов функций, заключенных в {...} ), обязательно завершайте последнюю функцию перед закрытием } ; ,

    • Только Linux:
      • sed -n '1 {p;q}' <<<$'a\nb' # -> 'a'
    • macOS и Linux:
      • sed -n '1 {p;q;}' <<<$'a\nb'

GNU sed -специальные функции, отсутствующие в BSD sed :

Возможности GNU вы пропустите, если вам нужно поддерживать обе платформы:

  • Различные варианты соответствия и замены регулярных выражений (как в шаблонах для выбора линии, так и в первом аргументе функции s ):

    • Параметр I для сопоставления регулярных выражений case-INsensitive (невероятно, BSD sed не поддерживает это вообще).
    • Параметр M для многострочного совпадения (где ^ / $ соответствует началу / концу каждой строки )
    • Дополнительные параметры, относящиеся к функции s , см. В https://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command
  • Эквивалентные последовательности

    • Вспомогательные escape-последовательности, такие как \u в аргументе замены функции s/// которые допускают манипуляции подстрокой , в пределах; например, sed 's/^./\u&/' <<<'dog' # -> 'Dog' - см. http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022 -command

    • Управляющие последовательности escape-последовательностей: в дополнение к \n , \t , ..., escape-пунктам на основе кода; например, все следующие escape-последовательности (шестнадцатеричные, восьмеричные, десятичные) представляют одну цитату ( ' ): \x27 , \o047 , \d039 - см. https://www.gnu.org/software/sed/manual/ sed.html # Escapes

  • Расширения адресов , такие как first~step чтобы соответствовать каждой шаг-й строке, addr, +N чтобы соответствовать N строкам после addr , ... - см. Http://www.gnu.org/software/sed/manual/sed. HTML # Адреса


[1] Версия macOS sed старше версии на других BSD-подобных системах, таких как FreeBSD и PC-BSD. К сожалению, это означает, что вы не можете предположить, что функции, которые работают в FreeBSD, например, будут работать [одинаково] на macOS.

[2] Строка с цитированием ANSI C $'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177' содержит все управляющие символы ASCII, кроме \n (и NUL), поэтому вы можете использовать его в сочетании с [:print:] для довольно надежной эмуляции [^\n] :
'[[:print:]'$'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177'']

Замените все символы новой строки на вкладки

Примечание. Для краткости команды используют здесь строки ( <<< ) и строки с котировкой ANSI C ( $'...' ) . Обе эти функции оболочки работают в bash , ksh и zsh .

# GNU Sed
$ sed ':a;$!{N;ba}; s/\n/\t/g' <<<$'line_1\nline_2\nline_3'
line_1 line_2 line_3

# BSD Sed equivalent (multi-line form)
sed <<<$'line_1\nline_2\nline_3' '
:a
$!{N;ba
}; s/\n/'$'\t''/g'

# BSD Sed equivalent (single-line form, via separate -e options)
sed -e ':a' -e '$!{N;ba' -e '}; s/\n/'$'\t''/g' <<<$'line 1\nline 2\nline 3'

BSD Sed отмечает:

  • Обратите внимание на необходимость прекращения меток ( :a ) и команд ветвления ( ba ) либо с фактическими символами новой строки, либо с отдельными параметрами -e .

  • Поскольку контрольно-символьные управляющие последовательности , такие как \t не поддерживаются в строке замены, вкладка ANSI C цитируемой буквальная сплайсируются в строку замены.
    регулярных выражениях части, BSD Sed распознает только \n в управляющей последовательности).

Добавить литерал в строку с функцией 'a'

Примечание. Для краткости команды используют здесь строки ( <<< ) и строки с котировкой ANSI C ( $'...' ) . Обе эти функции оболочки работают в bash , ksh и zsh .

 # GNU Sed
 $ sed '1 a appended text' <<<'line 1'
 line 1
 appended text

 # BSD Sed (multi-line form)
 sed '1 a\
 appended text' <<<'line 1'

 # BSD Sed (single-line form via a Bash/Ksh/Zsh ANSI C-quoted string)
 sed $'1 a\\\nappended text' <<<'line 1'

Обратите внимание, что для BSD Seed требуется \ последующей фактической новой строкой для добавления добавляемого текста.
То же самое относится к связанным функциям i (insert) и c (delete and insert).



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow