В BSD/macOS sed
, чтобы использовать новую строку в строке замены вызова функции s
, необходимо использовать действительную новую строку с \
-экранированием. - escape-последовательность \n
здесь не поддерживается (в отличие от regex части вызова).
Ибо: просто вставьте фактический перевод строки:
sed -i '' 's/\\n/\
/g' test1.txt
Или: используйте ANSI C-кавычки строка ($'...'
) для вставки новой строки ($'\n'
; работает в bash
, ksh
или zsh
):
sed -i '' 's/\\n/\'$'\n''/g' test1.txt
GNU sed
, напротив, распознает \n
в строках замены; прочтите всесторонний обзор различий между этими двумя реализациями.
Различия между GNU sed
(Linux) и BSD/macOS sed
macOS использует версию BSD sed
[1], которая во многих отношениях отличается от версии sed
GNU, поставляется с дистрибутивами Linux.
Их общим знаменателем является функциональность, определяемая POSIX: см. спецификация POSIX sed
Наиболее переносимый подход заключается в использовании только функций POSIX, что, однако, ограничивает функциональность:
- Notably, POSIX specifies support only for basic regular expressions, which have many limitations (e.g., no support for
|
(alternation) at all, no direct support for +
and ?
) and different escaping requirements.
- Caveat: GNU
sed
(without -r
), does support \|
, \+
and \?
, which is NOT POSIX-compliant; use --posix
to disable (see below).
- To use POSIX features only:
- (both versions): use only the
-n
and -e
options (notably, do not use -E
or -r
to turn on support for extended regular expressions)
- GNU
sed
: добавьте параметр --posix
, чтобы обеспечить функциональность только для POSIX (это не обязательно, но без него вы можете непреднамеренно использовать функции, отличные от POSIX, не заметив этого; предостережение: --posix
сам не POSIX-совместимый)
- Using POSIX-only features means stricter formatting requirements (forgoing many conveniences available in GNU
sed
):
- Control-character sequences such as
\n
and \t
are generally NOT supported.
- Метки и команды ветвления (например,
b
) должны сопровождаться фактической новой строкой или продолжением с помощью отдельной опции -e
.
- Подробнее см. ниже.
Однако обе версии реализуют расширения стандарта POSIX:
- какие расширения они реализуют, отличается (GNU
sed
реализует больше).
- даже те расширения, которые они оба реализуют, частично отличаются синтаксисом.
Если вам нужна поддержка ОБЕИХ платформ (обсуждение различий):
- Incompatible features:
- Use of the
-i
option without an argument (in-place updating without backup) is incompatible:
- BSD
sed
: MUST use -i ''
- GNU
sed
: НЕОБХОДИМО использовать только -i
(эквивалент: -i''
) — использование -i ''
НЕ работает.
-i
разумно включает нумерацию строк для каждого входного файла в GNU sed
и последних версиях BSD sed
(например, во FreeBSD 10), но НЕ работает в macOS версии 10.15.
Обратите внимание, что при отсутствии -i
все строки номеров версий кумулятивно во входных файлах.
- If the last input line does not have a trailing newline (and is printed):
- BSD
sed
: always appends a newline on output, even if the input line doesn't end in one.
- GNU
sed
: сохраняет статус завершающей новой строки, т. е. добавляет новую строку, только если входная строка заканчивается единицей.
- Common features:
- If you restrict your
sed
scripts to what BSD sed
supports, they will generally work in GNU sed
too - with the notable exception of using platform-specific extended regex features with -E
. Obviously, you'll also forgo extensions that are specific to the GNU version. See next section.
Рекомендации по кроссплатформенной поддержке (macOS/BSD, Linux), основанные на более строгих требованиях версии BSD:
Обратите внимание, что я использую сокращения macOS и Linux для версий BSD и GNU sed
соответственно, поскольку они являются стандартными версиями для каждой платформы. Однако можно установить GNU sed
на macOS, например, используя Homebrew с brew install gnu-sed
.
Примечание. За исключением случаев, когда используются флаги -r
и -E
(расширенные регулярные выражения), приведенные ниже инструкции сводятся к написание POSIX-совместимых сценариев sed
.
- Для соответствия POSIX вы должны ограничиться стандартами POSIX BRE (базовые< /em> регулярные выражения), которые, к сожалению, как следует из названия, довольно просты.
Предостережение: не думайте, что поддерживаются \|
, \+
и \?
: в то время как GNU sed
поддерживает их (если не используется --posix
), BSD sed
нет — эти функции не POSIX-совместимы.
В то время как \+
и \?
можно эмулировать в соответствии с POSIX :
\{1,\}
вместо \+
,
\{0,1\}
вместо \?
,
\|
(чередование) не может, к сожалению.
Для более мощных регулярных выражений используйте -E
(а не -r
) для поддержки ERE (расширенных регулярных выражений) (GNU sed
не документирует -E
, но там он работает как псевдоним -r
; более новая версия BSD sed
, например, во FreeBSD 10, теперь также поддерживает -r
, но версия macOS 10.10 нет em>).
Предостережение. Несмотря на то, что использование -r
/ -E
означает, что ваша команда по определению не совместима с POSIX, вы все равно должны ограничивать себя в ERE POSIX (расширенные регулярные выражения). К сожалению, это означает, что вы не сможете использовать несколько полезных конструкций, в частности:
- word-boundary assertions, because they're platform-specific (e.g.,
\<
on Linux, [[:<]]
on OS X).
- обратные ссылки внутри регулярных выражений (в отличие от «обратных ссылок» на совпадения группы захвата в строке замены
s
вызовов функций), поскольку BSD sed
не поддерживает их в расширенные регулярные выражения (но, что любопытно, делает то же самое в базовых, где они обязательны для POSIX).
Экран-последовательности управляющих символов, такие как \n
и \t
:
- In regexes (both in patterns for selection and the first argument to the
s
function), assume that only \n
is recognized as an escape sequence (rarely used, since the pattern space is usually a single line (without terminating \n
), but not inside a character class, so that, e.g., [^\n]
doesn't work; (if your input contains no control chars. other than \t
, you can emulate [^\n]
with [[:print:][:blank:]]
; otherwise, splice control chars. in as literals[2]) - generally, include control characters as literals, either via spliced-in ANSI C-quoted strings (e.g., $'\t'
) in shells that support it (bash,
ksh, zsh
), or via command substitutions using printf
(e.g., "$(printf '\t')"
).
- Linux only:
sed 's/\t/-/' <<<$'a\tb' # -> 'a-b'
- macOS и Linux:
sed 's/'$'\t''/-/' <<<$'a\tb' # ANSI C-quoted string
sed 's/'"$(printf '\t')"'/-/' <<<$'a\tb' # command subst. with printf
В строках замены, используемых с командой s
, предполагается, что escape-последовательности управляющих символов НЕ поддерживаются, поэтому снова включите управляющие символы. как литералы, как указано выше.
- Linux only:
sed 's/-/\t/' <<<$'a-b' # -> 'a<tab>b'
sed 's/-/\n/' <<<$'a-b' # -> 'a<newline>b'
- macOS и Linux:
sed 's/-/'$'\t''/' <<<'a-b'
sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
sed 's/-/\'$'\n''/' <<<'a-b'
Обратите внимание, что новые строки должны быть экранированы обратной косой чертой, чтобы они правильно интерпретировались как часть строки замены, а не как конец команды, и что использование printf
не работает для новых строк, поскольку завершающие новые строки удаляются при подстановке команд ($(...)
).
То же самое для текстовых аргументов функций i
и a
: не используйте последовательности управляющих символов — см. ниже.
- Labels and branching: labels as well as the label-name argument to the
b
and t
functions must be followed by either by a literal newline or a spliced-in $'\n'
. Alternatively, use multiple -e
options and terminate each right after the label name.
- Linux only:
sed -n '/a/ bLBL; d; :LBL p' <<<$'a\nb' # -> 'a'
- macOS and Linux:
- EITHER (actual newlines):
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'
- Functions
i
and a
for inserting/appending text: follow the function name by \
, followed either by a literal newline or a spliced-in $'\n'
before specifying the text argument.
- Linux only:
sed '1 i new first line' <<<$'a\nb' # -> 'new first line<nl>a<nl>b'
- macOS и Linux:
sed -e '1 i\'$'\n''new first line' <<<$'a\nb'
- Note:
- Without
-e
, the text argument is inexplicably not newline-terminated on output in macOS (bug?).
- Не используйте escape-символы, такие как
\n
и \t
, в текстовом аргументе, так как они поддерживаются только в Linux.
- Поэтому, если текстовый аргумент имеет фактические внутренние символы новой строки,
\
-экранируйте их.
- Если вы хотите поместить дополнительные команды после текстового аргумента, вы должны завершить его (неэкранированной) новой строкой (будь то литеральной или вставленной) или продолжить с отдельной опцией
-e
(это общее требование, применимое ко всем версиям).
Внутри функций, списков (несколько вызовов функций, заключенных в {...}
), не забудьте также завершить последнюю функцию перед закрытием }
, с ;
.
- Linux only:
sed -n '1 {p;q}' <<<$'a\nb' # -> 'a'
- macOS и Linux:
sed -n '1 {p;q;}' <<<$'a\nb'
С опцией -f
(для чтения команд из файла) только GNU sed
поддерживает -
в качестве заполнителя для стандартного ввода; используйте -f /dev/stdin
для переносимого чтения команд из стандартного ввода, в том числе из here-documents (при условии, что ваша платформа поддерживает /dev/stdin
, что обычно имеет место в настоящее время).
Специфические функции GNU sed
полностью отсутствуют в BSD sed
:
Возможности GNU, которые вы упустите, если вам нужна поддержка обеих платформ:
Различные параметры сопоставления и замены регулярных выражений (как в шаблонах для выбора строки, так и в первом аргументе функции s
):
Escape-последовательности
Управляющие последовательности, связанные с заменой, такие как \u
в аргументе замены функции s///
, которые позволяют манипулировать подстрокой в определенных пределах; например, sed 's/^./\u&/' <<<'dog' # -> 'Dog'
— см. http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command
Эскейп-последовательности управляющих символов: в дополнение к \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
[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'']
person
mklement0
schedule
18.06.2014
sed -i 's/\\n/\n/g' input.txt
. - person McLovin   schedule 18.06.2014test1.txt
как сценарий sed, гдеt
— это команда, условный переход к метке с именемext1.txt
, которой, конечно же, не существует. Странно, что пустой аргумент необходим, но я думаю, что это отвлекающий маневр по отношению к проблеме с новой строкой. - person ooga   schedule 18.06.2014