sed
BSD / macOS Sed против GNU Sed против спецификации POSIX Sed
Поиск…
Вступление
Чтобы процитировать сообщение с @ SnoringFrog по созданию темы:
«Одна из самых больших ошибок при использовании sed - это сценарии, которые не работают (или преуспевают неожиданным образом), потому что они были написаны для одного, а не для другого. Простое сокращение более значительных различий было бы хорошим».
замечания
macOS использует версию BSD sed
[1] , которая во многом отличается от версии GNU sed
, поставляемой с дистрибутивами Linux .
Их общим знаменателем является функциональность, установленная POSIX : см. sed
POSIX sed
.
Самый портативный подход - использовать только функции POSIX , но, тем не менее, ограничивает функциональность :
В частности, POSIX определяет поддержку только для базовых регулярных выражений, которые имеют много ограничений (например, отсутствие поддержки
|
(чередование) вообще, без прямой поддержки+
и?
) И различных требования вылетающих.- Оговорка: GNU
sed
(без-r
), не поддерживает\|
,\+
и\?
, который НЕ соответствует POSIX; используйте--posix
для отключения (см. ниже).
- Оговорка: GNU
Использовать только функции 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 ''
НЕ работает.
- BSD
-i
разумно включает строку нумерации строк ввода в GNUsed
и последние версии BSDsed
(например, на FreeBSD 10), но не имеет значения для macOS с 10.12 .
Обратите внимание, что в отсутствие-i
всех версий число строк кумулятивно отображается во входных файлах.Если последняя строка ввода не имеет завершающей новой строки (и печатается):
- BSD
sed
: всегда добавляет новую строку на выходе, даже если строка ввода не заканчивается на один. - GNU
sed
: сохраняет статус конечной новой строки , т. Е. Добавляет новую строку только в том случае, если строка ввода заканчивается на одном.
- BSD
Общие характеристики:
- Если вы ограничите свои сценарии
sed
тем, что поддерживает BSDsed
, они, как правило, будут работать и в GNUsed
- с заметным исключением использования расширенных функций регулярного выражения, связанных с платформой, с-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 ( базовые регулярные выражения) , которые, к сожалению, как следует из названия, являются довольно базовыми.
Предостережение : не предполагайте, что\|
,\+
и\?
поддерживаются: хотя GNUsed
поддерживает их (если используется--posix
), BSDsed
не выполняет - эти функции не совместимы с POSIX.
В то время как\+
и\?
могут быть эмулированы в соответствии с POSIX:
\{1,\}
для\+
,
\{0,1\}
для\?
,
\|
(чередование) не может, к сожалению.Для более мощных регулярных выражений используйте
-E
(а не-r
) для поддержки ERE ( расширенные регулярные выражения) (GNUsed
не документирует-E
, но он работает там как псевдоним-r
; более новая версия BSDsed
, например, на FreeBSD 10, теперь также поддерживают-r
, но версия MacOS от 10.12 не делает).
Предостережение . Несмотря на то, что использование-r
/-E
означает, что ваша команда по определению не совместима с POSIX, вы все равно должны ограничивать себя POSIX ERE (расширенные регулярные выражения) . К сожалению, это означает, что вы не сможете использовать несколько полезных конструкций, в частности:- потому что они специфичны для платформы (например,
\<
на Linux,[[:<]]
на OS X). - обратные ссылки внутри регулярных выражений (в отличие от «обратных ссылок» на совпадения записей в заменяющей строке вызовов функций
s
), поскольку BSDsed
не поддерживает их в расширенных регулярных выражениях (но, что любопытно, делает это в базовые , где они предназначены для 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
- Только Linux:
В строках замещения, используемых с командой
s
, предположим, что NO управляющих последовательностей escape-символов поддерживается , так что опять же включите контрольные символы. как литералы , как указано выше.- Только Linux:
sed 's/-/\t/' <<<$'ab' # -> 'a<tab>b'
- macOS и Linux:
sed 's/-/'$'\t''/' <<<'a-b'
sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
- Только Linux:
То же самое для текстовых аргументов
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'
- EITHER (фактические строки новой строки):
- Только Linux:
Функции
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:
Внутри списков функций (несколько вызовов функций, заключенных в
{...}
), обязательно завершайте последнюю функцию перед закрытием}
;
,- Только Linux:
-
sed -n '1 {p;q}' <<<$'a\nb' # -> 'a'
-
- macOS и Linux:
-
sed -n '1 {p;q;}' <<<$'a\nb'
-
- Только Linux:
GNU sed
-специальные функции, отсутствующие в BSD sed
:
Возможности GNU вы пропустите, если вам нужно поддерживать обе платформы:
Различные варианты соответствия и замены регулярных выражений (как в шаблонах для выбора линии, так и в первом аргументе функции
s
):- Параметр
I
для сопоставления регулярных выражений case-INsensitive (невероятно, BSDsed
не поддерживает это вообще). - Параметр
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).