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

этот вопрос уже есть ответ здесь:

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

и у меня есть файл " test1.txt", который содержит строку hellongoodbye

I используйте эту команду для поиска и замены "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'

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

2 ответов


с BSD / macOS sed, чтобы использовать новую строку в строку замены на s вызов функции, вы должны использовать \-сбежал фактический newline - escape sequence \n is не поддерживается там (в отличие от выражение часть Call).

  • или: просто вставить фактический строки:

    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 spec.

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

  • Примечательно, что POSIX указывает поддержка только для basic регулярные выражения, которые имеют много ограничений (например, нет поддержки | (чередование) вообще, без прямой поддержки + и ?) и различные экранирующие требования.
    • предостережение: GNU sed (без -r), тут поддержка \|, \+ и \?, который не совместим с POSIX; используйте --posix отключить (см. ниже).
  • использовать только функции POSIX:
    • (обе версии): используйте только на -n и -e параметры (в частности, не использовать -E или -r to включите поддержку продлен регулярные выражения)
    • GNU sed добавить параметр --posix для обеспечения функциональности POSIX-only (вам это не нужно, но без этого вы можете случайно использовать функции, отличные от POSIX, не заметив; предостережение: --posix is не POSIX-совместимая)
    • использование функций только POSIX означает более строгие требования к форматированию (отказ от многих удобства в GNU sed):
      • управляющие последовательности символов, такие как \n и \t обычно не поддерживаются.
      • метки и команды ветвления (например,b) должны за ним следует фактический новая строка или продолжение через отдельный .
      • Подробнее см. ниже.

, и варианты реализации расширения к стандарту POSIX:

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

Если вам нужно поддержать обе платформы (обсуждение различия):

  • несовместимо функции:
    • использование -i опции без аргумент (обновление на месте без резервного копирования) несовместимо:
      • BSD sed: должны использовать -i ''
      • GNU sed: необходимо использовать только -i (эквивалент: -i'') - С помощью -i '' не работает.
    • -i разумно включается per-input-file нумерация строк на GNU sed и последние версии BSD sed (например, на FreeBSD 10), но не не на macOS по состоянию на 10.12.
      Обратите внимание, что при отсутствии -i все версии количество строк в совокупности во входные файлы.
    • если последние входной линии не есть трейлинг newline (и печатается):
      • BSD sed: всегда добавляет новую строку на выходе, даже если входная строка не заканчивается в один.
      • GNU sed: сохраняет статус трейлинг-новой строки, т. е. он добавляет новую строку, только если входная строка заканчивается на одну.
  • общие особенности:
    • если вы ограничиваете свой sed скрипты к чему BSD sed поддерживает, они обычно работают в GNU sed тоже - за исключением использования платформы продлен regex особенности с -E. Очевидно, вы также откажетесь от расширений, специфичных для версии GNU. См. следующий раздел.

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

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

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

  • для соответствия POSIX вы должны ограничить себя POSIX BREs ( basic регулярные выражения), которые, к сожалению, как следует из названия, довольно просты.
    предостережение: do не предполагайте, что \|, \+ и \? поддерживаются: в то время как GNU sed их поддерживает (если --posix используется), BSD sed не - эти функции не POSIX-совместимыми.
    В то время как \+ и \? can эмулируются в POSIX-совместимой моде:
    \{1,\} на \+,
    \{0,1\} на \?,
    \| (попеременно) не может, к сожалению.
  • для более мощных регулярных выражений использовать -E (а не -r) для поддержки EREs (продлен регулярные выражения) (GNU sed не документ -E, но он работает там, как псевдоним -r; новая версия BSD sed, например, на FreeBSD 10, теперь поддержка -r, но версия macOS по состоянию на 10.10 делает не).
    предостережение: хотя использование -r / -E означает, что команда по определению не POSIX-совместимый, вы должны еще ограничивать себя POSIX EREs (расширенные регулярные выражения). К сожалению, это означает, что вы не сможете использовать несколько полезных конструкций, в частности:

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

  • метки и ветвления: метки, а также имя метки аргумент до b и t функции должен сопровождаться либо литерал newline или сплайсинга в $'\n'. Кроме того, используйте несколько -e options и завершите каждый сразу после имени метки.
    • 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'
  • функции i и a для вставки / добавления текста: следовать имя функции \, следовал по литерал newline или сплайсинга в $'\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 (ошибка?).
      • не используйте управляющие символы escapes например \n и \t в текстовом аргументе, поскольку они поддерживаются только в Linux.
      • если текстовый аргумент поэтому имеет фактические внутренние новые строки,\-убежать от них.
      • если вы хотите разместить дополнительные команды после текстового аргумента, вы должны завершить его (без эскапады) новой строкой (будь то литерал или сращивание) или продолжить с отдельным (это общее требование, которое применяется ко всем версии.)
  • внутри функции списки (несколько вызовов функций, заключенных в {...}), не забудьте также расторгнуть последние функция, до закрытия } с ;.
    • Linux только:
    • sed -n '1 {p;q}' <<<$'a\nb' # -> 'a'
    • macOS и Linux:
    • sed -n '1 {p;q;}' <<<$'a\nb'

GNU sedособенности отсутствует в BSD sed всего:

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

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

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

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

    • управляющие символы escape-последовательности: в дополнение к \n, \t, ..., escapes на основе codepoint; например, все следующие escapes (hex., восьмеричный, десятичный) представляют собой одинарную кавычку ('): \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#Addresses


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

[2] строка с кавычками ANSI $'1234567013456701234567012345677' содержит все символы управления ASCII, кроме \n (и NUL), поэтому вы можете использовать его в сочетании с [:print:] для довольно надежной эмуляции [^\n]:
'[[:print:]'$'1234567013456701234567012345677'']


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

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