sed не дает мне правильную операцию замены для новой строки с Mac – различия между GNU sed и BSD / OSX sed

Я использую эту ссылку: sed help: сопоставление и замена литерала «\ n» (а не новой строки)

и у меня есть файл “test1.txt”, который содержит строку hello \ ngoodbye

Я использую эту команду для поиска и замены «\ n» фактическими новыми строковыми символами:

sed -i '' 's/\\n/\n/g' test1.txt 

но результат: hellongoodbye . он просто заменяет «\ 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' 

Не знаю, почему я не могу заставить это работать. Заранее спасибо.

С помощью BSD / macOS sed , чтобы использовать новую строку в заменяющей строке вызова функции s , вы должны использовать \ -escaped фактическую новую строку – 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 в строках замещения; читайте дальше для всестороннего обзора различий между этими двумя реализациями.


Различия между sed GNU sed (Linux) и BSD / macOS

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

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

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

  • Примечательно, что POSIX указывает поддержку только для основных регулярных выражений , которые имеют множество ограничений (например, отсутствие поддержки для (альтернатива) вообще, отсутствие прямой поддержки для + и ? ) И различные требования к экранированию.
    • Caveat: 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 для версий BSD и GNU sed соответственно, потому что они являются версиями акций на каждой платформе. Тем не менее, можно установить GNU sed на macOS, например, используя Homebrew с brew install gnu-sed .

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

  • Для соответствия 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.10 не работает).
    Предостережение . Несмотря на то, что использование -r / -E означает, что ваша команда по определению не совместима с POSIX, вы все равно должны ограничивать себя POSIX ERE (расширенные регулярные выражения) . К сожалению, это означает, что вы не сможете использовать несколько полезных конструкций, в частности:

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

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

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

  • Ярлыки и ветвление : метки, а также аргумент имени метки для функций 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'
      • ИЛИ (несколько вариантов):
        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 lineab'
    • macOS и 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'']

Это может показаться немного странным, но попробуйте:

 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 указано, что расширение не является необязательным, и если вы его не хотите, вы должны указать пустой аргумент. Так что все имеет смысл в конце концов!

  • Возможно ли избежать метасимволов регулярных выражений с помощью sed
  • Использование sed для массового переименования файлов
  • sed -i +, что тот же вариант в SOLARIS
  • Как использовать замену новой строки в BSD sed?
  • Удаление цветовых кодов ANSI из текстового потока
  • Как использовать sed для замены только первого вхождения в файл?
  • Как конвертировать HTML-теги в RTF или любой текст в формате форматирования из командной строки Linux
  • Использование sed, Вставить строку ниже (или выше) шаблона?
  • sed с переменными bash
  • Замените все пробелы меткой разрыва строки / абзаца, чтобы сделать список слов
  • Новые строки в sed на Mac OS X
  • Interesting Posts

    Server.MapPath – указанный физический путь, ожидаемый виртуальный путь

    Определение последней строки в одном столбце

    jquery .live (‘click’) vs .click ()

    Parse цитирует строки с boost :: spirit

    Холст HTML5 100% Ширина Высота видового экрана?

    C # Справка по чтению иностранных символов с помощью StreamReader

    Как подключить Bluetooth-устройства с помощью API BluetoothHeadset

    Могу ли я перенести файлы с GoPro 3 на мой компьютер через Wi-Fi?

    Внешний жесткий диск не может безопасно удалить

    пакет локальной установки npm для настраиваемого местоположения

    2016: 2 пользователя одновременно на одном ПК Win 7/8, 2-й пользователь редактирует только несколько файлов Excel?

    Поддерживает ли Stream.forEce порядок столкновений последовательных streamов?

    Вопрос с интервью: три массива и O (N * N)

    Добавить пользовательский заголовок на основе типа файла

    Как я могу получить доступ к моему мини-компьютеру (RaspberryPi / MK802 / Mele A1000 / VIA APC) через ethernet / wifi без монитора?

    Давайте будем гением компьютера.