Подтвердить что ты не робот

Вставить строку в sed (Mac OS X)

Как вставить новую строку в заменяющую часть sed?

Этот код не работает:

sed "s/\(1234\)/\n\1/g" input.txt > output.txt

где input.txt:

test1234foo123bar1234

и output.txt должно быть:

test
1234foo123bar
1234

но insted я получаю это:

testn1234foo123barn1234

Примечание:

Этот вопрос касается версии Mac для Mac OS X, и сообщество отметило, что оно ведет себя иначе, чем, скажем, версии Linux.

4b9b3361

Ответ 1

Ваша версия sed, по-видимому, не поддерживает \n в RHS (правая часть подстановки). Вы должны прочитать часто задаваемые вопросы SED, которые поддерживает Эрик Пейнт, чтобы выбрать одно из возможных решений. Я предлагаю попробовать сначала вставить буквенный символ новой строки.

Ниже приведена цитата из него.


4.1. Как вставить новую строку в RHS подстановки?

Несколько версий sed allow \n должны быть введены непосредственно в RHS, которые затем преобразуются в новую строку на выходе: ssed, gsed302a +, gsed103 (с переключателем -x), sed15 +, sedmod и UnixDOS sed, Самое простое решение - использовать одну из этих версий.

Для других версий sed попробуйте выполнить одно из следующих действий:

(a) Если вы набрали sed script из оболочки Bourne, используйте один обратный слэш \, если script использует "одинарные кавычки" или две обратные косые черты \\, если script требует "двойных кавычек". В приведенном ниже примере обратите внимание, что ведущий > на второй строке генерируется оболочкой, чтобы запрашивать у пользователя больше ввода. Пользователь вводит косой чертой, одинарной кавычкой и затем ENTER для завершения команды:

 [sh-prompt]$ echo twolines | sed 's/two/& new\
 >/'
 two new
 lines
 [bash-prompt]$

(b) Используйте script файл с одним обратным слэшем \ в script, за которым следует новая строка. Это добавит новую строку в часть "replace". Пример:

 sed -f newline.sed files

 # newline.sed
 s/twolines/two new\
 lines/g

Некоторым версиям sed может не понадобиться обратная косая черта. Если это так, удалите его.

(c) Вставьте неиспользуемый символ и проведите вывод через tr:

 echo twolines | sed 's/two/& new=/' | tr "=" "\n"   # produces
 two new
 lines

(d) Используйте команду G:

G добавляет новую строку, а также содержимое пространства удержания в конец пространства шаблонов. Если пространство удержания пуст, в любом случае добавляется новая строка. Новая строка хранится в пространстве шаблонов как \n, где ее можно решить, группируя \(...\) и перемещаясь в RHS. Таким образом, чтобы изменить использованный ранее пример "twolines", будет работать следующее script:

 sed '/twolines/{G;s/\(two\)\(lines\)\(\n\)/\1\3\2/;}'

(e) Вставка полных строк, а не разрыв строк:

Если вы не меняете строки, а только вставляете полные строки до или после шаблона, процедура намного проще. Используйте команду i (insert) или a (добавление), внеся изменения внешним script. Вставить This line is new ПЕРЕД каждой строкой, соответствующей регулярному выражению:

 /RE/i This line is new               # HHsed, sedmod, gsed 3.02a
 /RE/{x;s/$/This line is new/;G;}     # other seds

Два вышеприведенных примера предназначены как "однострочные" команды, введенные с консоли. Если с помощью sed script, i\, за которым следует буквальная новая строка, будет работать на всех версиях sed. Кроме того, команда s/$/This line is new/ будет работать, только если пространство удержания уже пусто (по умолчанию оно).

Чтобы добавить This line is new ПОСЛЕ каждой строки, соответствующей регулярному выражению:

 /RE/a This line is new               # HHsed, sedmod, gsed 3.02a
 /RE/{G;s/$/This line is new/;}       # other seds

Чтобы добавить две пустые строки после каждой строки, соответствующей регулярному выражению:

 /RE/{G;G;}                    # assumes the hold space is empty

Чтобы заменить каждую строку, соответствующую регулярному выражению, на 5 пустых строк:

 /RE/{s/.*//;G;G;G;G;}         # assumes the hold space is empty

(f) Используйте команду y///, если это возможно:

В некоторых версиях sed (не GNU sed!) Unix, хотя команда s/// не принимает \n в RHS, команда y/// делает. Если ваш Unix sed поддерживает его, новая строка после aaa может быть вставлена ​​таким образом (которая не переносима для GNU sed или других seds):

 s/aaa/&~/; y/~/\n/;    # assuming no other '~' is on the line!

Ответ 2

Здесь однострочное решение, которое работает с любым совместимым с POSIX sed (включая версию FreeBSD на OSX), , предполагая, что ваша оболочка bash или ksh или zsh

sed 's/\(1234\)/\'$'\n''\1/g' <<<'test1234foo123bar1234'

Обратите внимание, что вы можете использовать одну строку с цитированием ANSI C как целую sed script, sed $'...' <<<, но это потребовало бы \ -извлечения всех экземпляров \ (удвоение их), что довольно громоздко и затрудняет читаемость, о чем свидетельствует @tovk answer).

  • $'\n' представляет новую строку и представляет собой экземпляр цитирование ANSI C, что позволяет создавать строки с управляющими символами.
  • Вышеупомянутый связывает строку с кавычками ANSI в sed script следующим образом:
    • script просто разбит на 2 строки с одной кавычкой, а строка с кодами ANSI C, заключенная между двумя половинами:
    • 's/\(1234\)/\' - это первая половина - обратите внимание, что она заканчивается на \, чтобы избежать новой строки, которая будет вставлена ​​как следующий char. (это экранирование необходимо для отметьте новую строку как часть строки замены, а не интерпретируйте ее как конец команды).
    • $'\n' - это ANSI C-кавычное представление символа новой строки, , которое оболочка расширяется до фактической строки новой строки перед передачей script в sed.
    • '\1/g' - вторая половина.

Обратите внимание, что это решение работает аналогично для других управляющих символов, таких как $'\t' для представления символа табуляции.


Фоновая информация:

  • Спецификация POSIX sed: http://man.cx/sed
    • BSD sed (также используемый в OSX) остается рядом с этой спецификацией, а GNU sed предлагает множество расширений.
  • Резюме различий между GNU sed и BSD sed можно найти на fooobar.com/questions/41949/...

Ответ 3

Версия Solaris sed Я мог бы убедить работать таким образом (в bash):

echo test1234foo123bar1234 | sed 's/\(1234\)/\
\1/g'

(вы должны поместить разрыв строки сразу после обратной косой черты).

В csh мне пришлось поставить еще одну обратную косую черту:

echo test1234foo123bar1234 | sed 's/\(1234\)/\\
\1/g'

Версия Gnu sed просто работала с помощью \n:

echo test1234foo123bar1234 | sed 's/\(1234\)/\n\1/g'

Ответ 4

Perl предоставляет более богатый "расширенный" синтаксис регулярных выражений, который здесь полезен:

perl -p -e 's/(?=1234)/\n/g'

означает "подставить новую строку для соответствия нулевой ширины после шаблона 1234". Это позволяет избежать захвата и повторения части выражения с помощью обратных ссылок.

Ответ 5

К сожалению, для меня sed, кажется, игнорирует \n в заменяющей строке.

$ echo test1234foo123bar1234 | sed "s/\(1234\)/\n\1/g"
testn1234foo123barn1234

Если это случится и для вас, альтернативой будет использование:

$ echo test1234foo123bar1234 | sed "s/\(1234\)/\\`echo -e '\n\r'`\1/g"

Это должно работать где угодно и будет производить:

test
1234foo123bar
1234

Для вашего примера с файлом input.txt в качестве ввода и output.txt в качестве вывода используйте:

$ sed "s/\(1234\)/\\`echo -e '\n\r'`\1/g" input.txt > output.txt

Ответ 6

Получите GNU sed.

$ brew install gnu-sed

Затем ваша команда будет работать как ожидалось:

$ gsed "s/\(1234\)/\n\1/g" input.txt
test
1234foo123bar
1234

nb: вы можете получить GNU sed благодаря малым портам.

Ответ 7

Попробуйте следующее:

$ echo test1234foo123bar1234 | sed "s/\(1234\)/\n\1/g"
test
1234foo123bar
1234

Из Sed Gnu doc ​​

g
    Apply the replacement to all matches to the regexp, not just the first. 

Ответ 8

Вы также можете использовать функцию $'string' для Bash:

man bash | less -p "\\$'"

printf  '%s' 'test1234foo123bar1234'  | sed $'s/\\(1234\\)/\\\n\\1/g'

Ответ 9

Новая строка в середине команды может чувствовать себя немного неуклюжей:

$ echo abc | sed 's/b/\
/'
a
c

Вот два решения этой проблемы, которые, я думаю, должны быть довольно переносимыми (должен работать для любых POSIX-совместимых sh, printf и sed):

Решение 1:

Не забудьте оставить символы \ и % для printf здесь:

$ echo abc | sed "$(printf 's/b/\\\n/')"
a
c

Чтобы избежать необходимости экранирования \ и % символов для printf:

$ echo abc | sed "$(printf '%s\n%s' 's/b/\' '/')"
a
c

Решение 2:

Сделайте переменную, содержащую новую строку следующим образом:

newline="$(printf '\nx')"; newline="${newline%x}"

Или вот так:

newline='
'

Затем используйте его следующим образом:

$ echo abc | sed "s/b/\\${newline}/"
a
c