Сед не дает мне правильную операцию замены для новой строки с Mac - различия между GNU sed и BSD / OSX sed
Я использую эту ссылку: sed help: сопоставление и замена литерала "\n" (не перевод строки)
и у меня есть файл "test1.txt", который содержит строку привет \ngoodbye
Я использую эту команду для поиска и замены "\ n" на новые символы новой строки:
sed -i '' 's/\\n/\n/g' test1.txt
но результат: чертовски до свидания. он просто заменяет "\ n" на "n", а не на новую строку. Это делает то же самое с / t, где он оставляет "t", а не вкладку.
'' для неопределенной ошибки в MAC: http://mpdaugherty.wordpress.com/2010/05/27/difference-with-sed-in-place-editing-on-mac-os-x-vs-linux/
Обновление:
Я попробовал обе команды, предложенные @hek2mgl:
sed -i 's/\\n/\n/g' test.txt
# Or:
sed -i'' 's/\\n/\n/g' test.txt
Хотя они могут работать с Linux, с MAC OS я получил следующую ошибку:
sed: 1: "test1.txt": undefined label 'est1.txt'
Не уверен, почему я не могу заставить это работать. Заранее спасибо.
2 ответа
С BSD / macOS sed
, чтобы использовать новую строку в строке замены s
вызов функции, вы должны использовать \
-экранированный фактический перевод строки -escape-последовательность \n
там не поддерживается (в отличие от регулярных выражений вызова).
Либо: просто вставьте актуальный перевод строки:
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], который во многом отличается от GNU sed
версия, которая поставляется с дистрибутивами Linux.
Их общим знаменателем является функциональность, определенная POSIX: см. 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
реализует больше). - даже те расширения, которые они оба реализуют, частично отличаются по синтаксису.
Если вам нужна поддержка ОБА платформ (обсуждение различий):
- Несовместимые функции:
- Использование
-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 для версий BSD и GNU sed
соответственно потому что они стоковые версии на каждой платформе. Тем не менее, есть возможность установить GNU sed
на macOS, например, используя Homebrew с brew install gnu-sed
,
Примечание: за исключением случаев, когда -r
а также -E
используются флаги (расширенные регулярные выражения), приведенные ниже инструкции сводятся к написанию POSIX-совместимых sed
скрипты.
- Для соответствия POSIX вы должны ограничить себя POSIX BRE (базовыми регулярными выражениями), которые, к сожалению, как следует из названия, довольно просты.
Предостережение: не предполагайте, что\|
,\+
а также\?
поддерживаются: пока GNUsed
поддерживает их (если--posix
используется), BSDsed
нет - эти функции не совместимы с POSIX.
В то время как\+
а также\?
можно эмулировать в POSIX-совместимом режиме:\{1,\}
за\+
,\{0,1\}
за\?
,\|
(чередование) не может, к сожалению. Для более мощных регулярных выражений используйте
-E
(скорее, чем-r
) для поддержки ERE (расширенные регулярные выражения) (GNUsed
не документирует-E
, но это работает там как псевдоним-r
; более новая версия BSDsed
, такие как на FreeBSD 10, теперь также поддерживают-r
, но версия macOS по состоянию на 10.10 нет).
Будьте внимательны-r
/-E
означает, что ваша команда по определению не POSIX-совместимая, вы все равно должны ограничивать себя POSIX ERE (расширенными регулярными выражениями). К сожалению, это означает, что вы не сможете использовать несколько полезных конструкций, а именно:- словосочетания, потому что они зависят от платформы (например,
\<
в Linux,[[:<]]
на OS X). - обратные ссылки внутри регулярных выражений (в отличие от обратных ссылок на совпадения групп захвата в строке замены
s
вызовы функций), потому что BSDsed
не поддерживает их в расширенных регулярных выражениях (но, как ни странно, делает это в базовых регулярных выражениях, где они являются обязательными для POSIX).
- словосочетания, потому что они зависят от платформы (например,
Escape-последовательности управляющих символов, такие как
\n
а также\t
:- В регулярных выражениях (как в шаблонах для выбора, так и в первом аргументе
s
функция), предположим, что только\n
распознается как escape-последовательность (редко используется, так как пространство шаблона обычно представляет собой одну строку (без завершения\n
), но не внутри класса символов, так что, например,[^\n]
не работает; (если ваш ввод не содержит контрольных символов. кроме\t
Вы можете подражать[^\n]
с[[:print:][:blank:]]
; в противном случае соедините контрольные символы. в качестве литералов [2]) - обычно включают управляющие символы в качестве литералов либо через встроенные строки ANSI C в кавычках (например,$'\t'
) в снарядах, которые его поддерживают (bash,
КШ,zsh
), или с помощью подстановок команд, используяprintf
(например,"$(printf '\t')"
)- Только для Linux:
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
- Только для Linux:
В замене строк, используемых с
s
команда, предположим, что никакие управляющие последовательности управляющих символов не поддерживаются, поэтому снова включите управляющие символы. как литералы, как указано выше.- Только для Linux:
sed 's/-/\t/' <<<$'a-b' # -> 'a<tab>b'
- macOS и Linux:
sed 's/-/'$'\t''/' <<<'a-b'
sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
- Только для Linux:
То же самое для текстовых аргументов
i
а такжеa
функции: не используйте последовательности управляющих символов - см. ниже.
- В регулярных выражениях (как в шаблонах для выбора, так и в первом аргументе
- Метки и разветвление: метки, а также аргумент label-name для
b
а такжеt
за функциями должен следовать буквальный перевод строки или врезка$'\n'
, В качестве альтернативы используйте несколько-e
варианты и завершить каждый сразу после названия метки.- Только для Linux:
sed -n '/a/ bLBL; d; :LBL p' <<<$'a\nb' # -> 'a'
- macOS и Linux:
- ИЛИ (фактические новые строки):
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'
- ИЛИ (фактические новые строки):
- Только для Linux:
- функции
i
а такжеa
для вставки / добавления текста: следуйте названию функции\
с последующим буквальным переводом строки или вставкой$'\n'
перед указанием текстового аргумента.- Только для Linux:
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'
- Замечания:
- Без
-e
текстовый аргумент необъяснимо не завершается символом новой строки при выводе в macOS (ошибка?). - Не используйте экранированные символы, такие как
\n
а также\t
в текстовом аргументе, так как они поддерживаются только в Linux. - Если текстовый аргумент имеет фактические внутренние переводы строк,
\
-Сохраните их. - Если вы хотите поместить дополнительные команды после текстового аргумента, вы должны завершить его новой (неэкранированной) новой строкой (литеральной или врезанной) или продолжить с отдельной
-e
опция (это общее требование, которое применяется ко всем версиям).
- Без
- Только для Linux:
- Внутри списков функций (несколько вызовов функций заключены в
{...}
), обязательно завершите последнюю функцию перед закрытием}
, с;
,- Только для 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
опция для нечувствительного к регистру сопоставления регулярных выражений (невероятно, BSDsed
не поддерживает это вообще). -
M
опция для многострочного соответствия (где^
/$
сопоставить начало / конец каждой строки) - Для дополнительных опций, которые относятся к
s
функцию см. https://www.gnu.org/software/sed/manual/sed.html
-
Escape-последовательности
Связанные с замещением escape-последовательности, такие как
\u
в аргументе заменыs///
функция, позволяющая манипулировать подстрокой в определенных пределах; например,sed 's/^./\u&/' <<<'dog' # -> 'Dog'
- см. http://www.gnu.org/software/sed/manual/sed.html.Escape-последовательности управляющих символов: в дополнение к
\n
,\t
..., экранированные коды; например, все следующие экранированные символы (шестнадцатеричные, восьмеричные, десятичные) представляют одну кавычку ('
):\x27
,\o047
,\d039
- см. https://www.gnu.org/software/sed/manual/sed.html
Расширения адресов, такие как
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'']
Это может показаться немного странным, но попробуйте:
sed -i '' 's/\\n/\
/g' test1.txt
Т.е. используйте актуальный перевод строки вместо \n
,
Объяснение в том, что у вас странный sed
! Подробности см. В руководстве по mac sed: https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/sed.1.html
В описании s
там команда говорит:
A line can be split by substituting a newline character into it. To specify
a newline character in the replacement string, precede it with a backslash.
Также в описании -i
опция говорит, что расширение не является обязательным, и что если вы не хотите его использовать, вы должны указать пустой аргумент. Так что все имеет смысл в конце концов!