Как вставить новую строку перед шаблоном?

Как вставить новую строку перед шаблоном внутри строки?

Например, это вставит новую строку после шаблона регулярного выражения.

sed 's/regex/&\n/g'

Как сделать то же самое, но перед шаблоном?

Учитывая этот образец входного файла, шаблон для сопоставления — это номер телефона.

some text (012)345-6789

Должен стать

some text
(012)345-6789

person Dennis    schedule 06.04.2009    source источник
comment
Просто повторяю ответ на Как вставить новую строку/разрыв строки после строки с помощью sed здесь: sed '/regex/G'   -  person Adam Schmideg    schedule 02.05.2019
comment
@NilsvonBarth, почему простой вопрос — плохой вопрос?   -  person Josh    schedule 24.10.2019


Ответы (17)


Это работает в bash и zsh, проверено на Linux и OS X:

sed 's/regexp/\'$'\n/g'

В общем, для $, за которым следует строковый литерал в одинарных кавычках, bash выполняет замену обратной косой черты в стиле C, например. $'\t' переводится в буквальную вкладку. Кроме того, sed хочет, чтобы ваш литерал новой строки был экранирован обратной косой чертой, следовательно, \ перед $. И, наконец, сам знак доллара не должен заключаться в кавычки, чтобы он интерпретировался оболочкой, поэтому мы закрываем кавычки перед $, а затем снова открываем.

Изменить. Как было предложено в комментариях @mklement0, это также работает:

sed $'s/regexp/\\\n/g'

Здесь происходит следующее: вся команда sed теперь представляет собой строку в стиле C, что означает, что обратная косая черта, которую sed требует поставить перед литералом новой строки, теперь должна быть экранирована другой обратной косой чертой. Хотя это и более читабельно, в этом случае вы не сможете выполнять замены строк оболочки (не делая их снова уродливыми).

person mojuba    schedule 22.06.2012
comment
Это дает мне неэкранированную новую строку внутри шаблона замены в OSX. - person Matt Gibson; 29.07.2013
comment
@Matt Gibson, это очень странно, потому что неэкранированная новая строка дается только тогда, когда у вас есть настоящая новая строка без обратной косой черты в шаблоне замены. Мой код выше работает, по сути, и в некоторых других оболочках, например. зш, кш. - person mojuba; 29.07.2013
comment
@ Мэтт Гибсон ... или если вы забудете обратную косую черту перед '$'\n в моем коде. - person mojuba; 29.07.2013
comment
+1 это фантастика, работает как в OSX, так и в Linux - person janos; 22.12.2013
comment
Как написано, эти выражения полностью заменяют регулярное выражение новой строкой, а не вставляют новую строку в середину существующей строки, как это требуется. Вот как я использовал модифицированную форму этого ответа, чтобы вставить новую строку между двумя совпадающими шаблонами: sed '\(first match\)\(second match\)/\1\'$'\n''\2/g'. Обратите внимание на две одинарные кавычки после \n. Первый закрывает секцию $, так что он не влияет на остальную часть строки. Без этих кавычек \2 игнорировался. - person David Ravetti; 28.07.2014
comment
@DavidRavetti не обязательно. Если вы знаете, что вы ищете, что вы делаете большую часть времени, то это должно быть так же просто, как s/AB/A\'$'\nB/ - person mojuba; 15.05.2015
comment
Другой вариант — использовать одиночный Строка в ANSI C-кавычках: sed $'s/regexp/\\\n/g', что улучшает читабельность — единственная оговорка заключается в том, что вам нужно удвоить все литеральные \ символы. - person mklement0; 30.11.2015
comment
Это сработало отлично и должно быть выбранным ответом... для остальных требуются альтернативные версии синтаксиса sed или платформы... - person jrypkahauer; 06.11.2020

Некоторые другие ответы не работали для моей версии sed. Переключение положения & и \n сработало.

sed 's/regexp/\n&/g' 

Изменить: похоже, это не работает в OS X, если вы не установите gnu-sed.

person Dennis    schedule 06.04.2009
comment
Я не уверен, что это работает во всех версиях sed. Я попробовал это на своем Mac, и \n просто выводится как «n» - person Todd Gamblin; 07.04.2009
comment
Провел 15 минут на Mac на работе, прежде чем прочитать ваш ответ. Давай Эппл! - person Rick77; 07.07.2015
comment
Для тех, кто использует доморощенный: brew install gnu-sed, а затем gsed 's/regexp/\n&/g' - person aaaaaa; 05.05.2016
comment
...а затем echo 'alias sed=gsed' >> ~/.bashrc - person Proximo; 12.08.2018

В sed вы не можете легко добавлять новые строки в выходной поток. Вам нужно использовать строку продолжения, что неудобно, но работает:

$ sed 's/regexp/\
&/'

Пример:

$ echo foo | sed 's/.*/\
&/'

foo

Подробнее см. здесь. Если вы хотите что-то менее неудобное, вы можете попробовать использовать perl -pe с группами соответствия вместо sed:

$ echo foo | perl -pe 's/(.*)/\n$1/'

foo

$1 относится к первой соответствующей группе в регулярном выражении, где группы указаны в круглых скобках.

person Todd Gamblin    schedule 06.04.2009
comment
Почему вы говорите, что не можете добавлять новые строки? Вы можете просто сделать sed 's/regexp/&\n/g' - person Andres; 09.11.2012
comment
Это наименее хакерская вещь, которую вы можете сделать на Mac, чтобы вставить новую строку (\n не работает на Mac) - person Pylinux; 04.02.2015
comment
Версия perl может быть изменена для редактирования на месте perl -pi -e 's/(.*)/\n$1/' foo - person Eponymous; 08.05.2015
comment
@Andres: (в основном) реализации Sed только для функций POSIX, такие как версия BSD, которая также поставляется с OS X, не поддерживают escape-последовательности управляющих символов в части подстановки вызова функции s (в отличие от GNU реализация Sed, которая делает). Приведенный выше ответ работает с обеими реализациями; обзор всех различий см. здесь. - person mklement0; 30.11.2015

На моем Mac следующее вставляет одну букву «n» вместо новой строки:

sed 's/regexp/\n&/g'

Это заменяется новой строкой:

sed "s/regexp/\\`echo -e '\n\r'`/g"
person Roar Skullestad    schedule 27.09.2011
comment
Я выполнял встроенное редактирование sed -i '' -e ... и у меня возникли проблемы с записью в файл ^M каретки M (ctrl+m). В итоге я использовал Perl с теми же параметрами. - person Steve Tauber; 25.05.2013
comment
Обратите внимание на тот факт, что второй код вставляет специальный код новой строки LF CR (обратный код MS-DOS CR LF)! И Unix-подобные ОС, и Mac OS X используют только LF (\n). - person pabouk; 03.12.2013
comment
Что-то еще в моем выражении sed вызывало столько недовольства (несмотря на то, что оно отлично работало без echo... и новой строки), что я просто сделал это в vim. - person Ahmed Fasih; 17.01.2014
comment
Или просто: sed "s/regexp/`echo`/g" - это создаст один LF вместо LF-CR - person mojuba; 29.04.2014
comment
@mojuba: Нет: `echo` приведет к пустой строке, потому что подстановки команд неизменно обрезают все завершающие символы новой строки. Невозможно использовать подстановку команд для прямой вставки одной новой строки (и вставка \n\r, т. е. дополнительный CR, — ужасная идея). - person mklement0; 30.11.2015
comment
Я поставил \\`echo -e '\n\r'` там, где мне это было нужно, и это было достаточно хорошо. - person Jose Ramirez; 24.09.2019

Вы можете использовать однострочники perl так же, как и с sed, с преимуществом полного регулярного выражения perl поддержка (которая намного мощнее, чем та, что вы получаете с sed). Также очень мало различий между платформами * nix - perl, как правило, perl. Таким образом, вы можете перестать беспокоиться о том, как заставить версию sed вашей конкретной системы делать то, что вы хотите.

В этом случае вы можете сделать

perl -pe 's/(regex)/\n$1/'

-pe помещает perl в цикл "выполнить и распечатать", очень похожий на обычный режим работы sed.

' заключает в кавычки все остальное, чтобы оболочка не мешала

() вокруг регулярного выражения является оператором группировки. $1 в правой части подстановки выводит все, что было найдено внутри этих скобок.

Наконец, \n — это новая строка.

Независимо от того, используете ли вы круглые скобки в качестве оператора группировки, вы должны экранировать любые круглые скобки, которые вы пытаетесь сопоставить. Таким образом, регулярное выражение, соответствующее приведенному выше шаблону, будет выглядеть примерно так:

\(\d\d\d\)\d\d\d-\d\d\d\d

\( или \) соответствует буквальной скобке, а \d соответствует цифре.

Лучше:

\(\d{3}\)\d{3}-\d{4}

Я полагаю, вы можете понять, что делают числа в фигурных скобках.

Кроме того, вы можете использовать разделители, отличные от / для вашего регулярного выражения. Поэтому, если вам нужно сопоставить / вам не нужно будет его избегать. Любой из приведенных ниже эквивалентен регулярному выражению в начале моего ответа. Теоретически вы можете заменить любой символ для стандартного / с.

perl -pe 's#(regex)#\n$1#'
perl -pe 's{(regex)}{\n$1}'

Пара заключительных мыслей.

использование -ne вместо -pe действует аналогично, но не печатается автоматически в конце. Это может быть удобно, если вы хотите печатать самостоятельно. Например, вот похожий на grep (m/foobar/ соответствует регулярному выражению):

perl -ne 'if (m/foobar/) {print}'

Если вы находите работу с символами новой строки неприятными и хотите, чтобы они волшебным образом обрабатывались за вас, добавьте -l. Однако бесполезно для ОП, который работал с новыми строками.

Дополнительный совет: если у вас установлен пакет pcre, он поставляется с pcregrep, который использует полные perl-совместимые регулярные выражения.

person Dan Pritts    schedule 21.05.2014

В этом случае я не использую sed. Я использую тр.

cat Somefile |tr ',' '\012' 

Это берет запятую и заменяет ее возвратом каретки.

person user1612632    schedule 20.08.2012
comment
Я обнаружил, что это также работает: cat Somefile | tr ',' '\n' YMMV - person Mr. Lance E Sloan; 16.12.2016

Хм, кажется, что только экранированные символы новой строки работают в более поздних версиях sed (у меня GNU sed 4.2.1),

dev:~/pg/services/places> echo 'foobar' | sed -r 's/(bar)/\n\1/;'
foo
bar
person gatoatigrado    schedule 21.05.2014
comment
Как уже упоминалось, это работает с различными версиями GNU sed, но не с sed, включенным в macOS. - person Mr. Lance E Sloan; 16.12.2016

echo pattern | sed -E -e $'s/^(pattern)/\\\n\\1/'

отлично работал на El Captitan с поддержкой ()

person Quanlong    schedule 10.12.2015
comment
Это отлично сработало, и вы даже даете полную команду для тестирования и экстраполяции, чтобы специализироваться для своих собственных целей. Хорошая работа! - person jxramos; 20.04.2018

Чтобы вставить новую строку в поток вывода в Linux, я использовал:

sed -i "s/def/abc\\\ndef/" file1

Где file1 было:

def

Перед заменой sed на месте и:

abc
def

После замены sed на месте. Обратите внимание на использование \\\n. Если в шаблонах есть ", экранируйте с помощью \".

person Karthik    schedule 14.09.2012
comment
Для меня код выше не работает. sed вставляет \n вместо LF, потому что получает \\n в параметре из оболочки. --- Этот код работает: sed -i "s/def/abc\ndef/" file1. --- GNU sed version 4.2.1, GNU bash, version 4.1.2(1) / 4.2.25(1) (выпуск CentOS 6.4 / Ubuntu 12.04.3). - person pabouk; 03.12.2013

в sed вы можете ссылаться на группы в своем шаблоне с помощью «\ 1», «\ 2», .... поэтому, если вы ищете шаблон «ШАБЛОН», и вы хотите вставить перед ним «ДО» , вы можете использовать без экранирования

sed 's/(PATTERN)/BEFORE\1/g'

i.e.

  sed 's/\(PATTERN\)/BEFORE\1/g'
person Steve B.    schedule 06.04.2009
comment
Только что сделал: содержимое тестового файла=ABC ABC ABC. Запустил тестовый файл sed 's/\(ABC\)/\n\1/g', получил новые строки. Поэкспериментируйте с побегами, старайтесь добавлять в шаблон по одной вещи за раз, например. убедитесь, что вы соответствуете шаблону, затем проверьте соответствие группы, затем добавьте проверку новой строки. - person Steve B.; 07.04.2009
comment
Я только что попробовал именно это и получил nABC nABC nABC'. Вы используете какую-то другую версию sed? - person Todd Gamblin; 07.04.2009
comment
экранирование оболочки, вероятно, мешает попыткам tgamblin. помещение полных аргументов sed в одинарные кавычки, как это сделал Стив Б, должно исправить это. Однако возможно, что разные версии sed не понимают \n для новой строки. - person Dan Pritts; 21.05.2014

Вы также можете сделать это с помощью awk, используя -v для предоставления шаблона:

awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' file

Это проверяет, содержит ли строка заданный шаблон. Если это так, он добавляет новую строку к ее началу.

См. базовый пример:

$ cat file
hello
this is some pattern and we are going ahead
bye!
$ awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' file
hello
this is some 
pattern and we are going ahead
bye!

Обратите внимание, что это повлияет на все шаблоны в строке:

$ cat file
this pattern is some pattern and we are going ahead
$ awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' d
this 
pattern is some 
pattern and we are going ahead
person fedorqui 'SO stop harming'    schedule 28.07.2016
comment
что делает 1 в этом? - person whatahitson; 04.06.2018
comment
@whatahitson 1 используется в Awk как сокращение от {print $0}. Причина в том, что любое условие, оцениваемое как True, запускает действие Awk по умолчанию, заключающееся в печати текущей записи. - person fedorqui 'SO stop harming'; 04.06.2018

В моем случае работает следующий метод.

sed -i 's/playstation/PS4/' input.txt

Можно записать как:

sed -i 's/playstation/PS4\nplaystation/' input.txt

PS4
playstation

Рассмотрите возможность использования \\n при использовании его в строковом литерале.

  • sed: редактор потока

  • -i: позволяет редактировать исходный файл.

  • +: разделитель.

Я надеюсь, что приведенная выше информация работает для вас ????.

person vijayraj34    schedule 18.08.2020

Это работает в MAC для меня

sed -i.bak -e 's/regex/xregex/g' input.txt sed -i.bak -e 's/qregex/\'$'\nregex/g' input.txt

Доно ли это идеальный ...

person sam    schedule 25.10.2013

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

#!/bin/bash
# script: add_domain
# using fixed values instead of command line parameters $1, $2
# to show typical variable values in this example
ipaddr="127.0.0.1"
domain="example.com"
# no need to escape $ipaddr and $domain values if we use separate quotes.
sudo sed -i '$a \\n'"$ipaddr www.$domain $domain" /etc/hosts

Сценарий добавляет новую строку \n, за которой следует еще одна строка текста, в конец файла с помощью одной команды sed.

person Xavier    schedule 25.01.2016

sed -e 's/regexp/\0\n/g'

\0 — это null, поэтому ваше выражение заменяется на null (ничего), а затем...
\n — это новая строка

На некоторых разновидностях Unix не работает, но я думаю, что это решение вашей проблемы.

echo "Hello" | sed -e 's/Hello/\0\ntmow/g'
Hello
tmow
person tmow    schedule 13.12.2011

В vi для Red Hat я мог вставлять возврат каретки, используя только символ \r. Я полагаю, что это внутренне выполняет «ex» вместо «sed», но это похоже, и vi может быть еще одним способом выполнения массовых изменений, таких как исправления кода. Например. Я окружаю поисковый запрос оператором if, который настаивает на возврате каретки после фигурных скобок:

:.,$s/\(my_function(.*)\)/if(!skip_option){\r\t\1\r\t}/

Обратите внимание, что я также вставил несколько вкладок, чтобы все было лучше выровнено.

person Robert Casey    schedule 01.11.2012

person    schedule
comment
+1 работал отлично и довольно прямолинейно / легко запоминалось - person gMale; 26.06.2013
comment
Этот ответ на самом деле является решением sed, а не решением bash. Все, что использует такие конструкции, как $'\n', полагается на оболочку для создания новой строки. Такие решения могут быть не переносимыми. Этот. Конечно, это также дубликат второго примера в ответе tgamblin от 2009 года. - person ghoti; 03.12.2015