Вставить строку в 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.
Ответы
Ответ 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