Я заметил, что если я добавлю \n
шаблон для замены с использованием sed
, он не будет соответствовать. Пример:
$ cat > alpha.txt
This is
a test
Please do not
be alarmed
$ sed -i'.original' 's/a test\nPlease do not/not a test\nBe/' alpha.txt
$ diff alpha.txt{,.original}
$ # No differences printed out
Как я могу заставить это работать?
sed
regular-expression
utilities
Бельмин Фернандес
источник
источник
Ответы:
В простейшем вызове sed он имеет одну строку текста в пространстве шаблона, т.е. 1 строка
\n
текста с разделителями из ввода. У единственной строки в пространстве шаблонов нет\n
... Вот почему ваше регулярное выражение ничего не находит.Вы можете читать несколько строк в шаблонном пространстве и удивительно хорошо управлять вещами, но с усилиями, превышающими обычные. У Sed есть набор команд, которые позволяют такие вещи ... Вот ссылка на Сводку команд для sed , Это лучший, который я нашел, и заставил меня кататься.
Однако, если вы начнете использовать микро-команды sed, забудьте об идее «одной строки». Полезно выложить его как структурированную программу, пока не почувствуете это ... Это удивительно просто и не менее необычно. Вы можете думать об этом как о «языке ассемблера» редактирования текста.
Резюме: используйте sed для простых вещей, и, возможно, немного больше, но в целом, когда это выходит за рамки работы с одной строкой, большинство людей предпочитают что-то другое ...
Я позволю кому-то еще предложить что-то еще ... Я на самом деле не уверен, какой будет лучший выбор (я бы использовал sed, но это потому, что я недостаточно хорошо знаю Perl.)
Здесь тот же сценарий, сжатый в то, что, очевидно, труднее читать и работать, но некоторые сомнительно назвали бы одну строку
Вот моя команда "шпаргалка"
источник
t
команду здесь - если ей не дана метка, по умолчанию ветвление заканчивается в конце скрипта. Тоsed '/^a test$/{$!{N;s/^a test\nPlease do not$/not a test\nBe/;t;P;D}}' alpha.txt
же самое и ваша команда при любых обстоятельствах. Конечно, для этого конкретного файла,sed '/test/{N;s/.*/not a test\nBe/}' alpha.txt
делает то же самое, но мой первый пример логически эквивалентен для всех возможных файлов. Также обратите внимание, что\n
в строке замены не появляется символ новой строки; для этого вам понадобится обратная косая черта `\` с последующим символом новой строки.#
команда не отделена от предыдущего\n
в RHS ofs
). С GNUsed
вы также можете использовать-z
для использования записей с разделителями NUL (а затем делать пометку во всем вводе, если это текст (который по определению не содержит NUL)).Используйте
perl
вместоsed
:-pi -e
ваша стандартная последовательность командной строки «заменить на месте», а -0777 заставляет perl отбрасывать файлы целиком. Смотрите perldoc perlrun, чтобы узнать больше об этом.источник
sed
и отвечает, используя awk или perl. Я думаю, что это не по теме, следовательно, извините, но я выстрелил минус один.sed
ответ выше доказывает, что Perl ответ по теме.Я думаю, что лучше заменить
\n
символ другим символом, а затем работать как обычно:например, нерабочий исходный код:
можно изменить на:
Если кто-то не знает,
\n
конец строки UNIX,\r\n
- windows,\r
- классическая Mac OS. Обычный текст UNIX не использует\r
символ, поэтому его можно использовать в этом случае.Вы также можете использовать какой-нибудь экзотический символ для временной замены \ n. В качестве примера - \ f (символ перевода формы). Вы можете найти больше символов здесь .
источник
\r
аргумента наsed
with$(printf '\r')
.$
перед SED строки , чтобы предотвратить его преобразуя\r
вr
. Краткий пример:sed $'s/\r/~/'
. Полный пример:cat alpha.txt | tr '\n' '\r' | sed $'s/a test\rPlease do not/not a test\rBe/' | tr '\r' '\n'
Учитывая все обстоятельства, поглощение всего файла может быть самым быстрым способом.
Основной синтаксис выглядит следующим образом:
Имейте в виду, поглощение всего файла может быть невозможным, если файл очень большой. Для таких случаев другие ответы, представленные здесь, предлагают индивидуальные решения, которые гарантированно будут работать с небольшим объемом памяти.
Для всех других ситуаций, связанных с хакерством и косой чертой, простое предварительное добавление,
-e '1h;2,$H;$!d;g'
за которым следует исходныйsed
аргумент регулярного выражения, в значительной степени делает свою работунапример
Что делает
-e '1h;2,$H;$!d;g'
?1
,2,$
,$!
Часть линии спецификаторов этого предел , который выстилает непосредственно следующая команда работает на.1
: Только первая строка2,$
: Все строки, начиная со второго$!
: Каждая строка, кроме последнейТаким образом, это то, что происходит в каждой строке ввода N строк.
g
Команда не дала строки спецификатора, но предшествующаяd
команда имеет специальное положение « Пуск следующий цикл. », И это предотвращаетg
запуск на все линии , кроме последнего.Что касается значения каждой команды:
h
следуютH
с на каждой линии копий сказал линии ввода вsed
«ы трюма . (Вспомните произвольный текстовый буфер.)d
отбрасывает каждую строку для предотвращения записи этих строк в вывод. Держать пространство , однако сохраняется.g
восстанавливает накопление каждой строки из пространства удержания, чтобыsed
она могла выполнять свое регулярное выражение на всем входе (а не в виде строки за раз) и, следовательно, могла совпадение по\n
с.источник
sed
имеет три команды для управления операциями многострочных:N
,D
иP
(сравнить их нормальныеn
,d
аp
).В этом случае вы можете сопоставить первую строку вашего шаблона, использовать,
N
чтобы добавить вторую строку к пространству шаблона, а затем использоватьs
для выполнения замены.Что-то вроде:
источник
G
,H
,x
...). С помощьюs
команды также можно добавить больше строк в пространство шаблона .N
командВы можете, но это сложно . Я рекомендую перейти на другой инструмент. Если есть регулярное выражение, которое никогда не соответствует какой-либо части текста, которую вы хотите заменить, вы можете использовать его как разделитель записей awk в GNU awk.
Если в строке поиска никогда не бывает двух последовательных символов новой строки, вы можете использовать «режим абзаца» в awk (одна или несколько пустых строк разделяют записи).
Простое решение - использовать Perl и полностью загрузить файл в память.
источник
perl -0777 -pe '…' <input-file >output-file
. Чтобы изменить файл на месте,perl -0777 -i -pe '…' filename
sed
«s-z
вариант (добавлена в 2012 году после того, как этот ответ был отправлен):seq 10 | sed -z 's/4\n5/a\nb/'
.Я думаю, что это решение Sed для соответствия двух строк.
Если вы хотите, чтобы 3 строки соответствовали, то ...
Если вы хотите, чтобы 4 строки соответствовали, то ...
Если заменяющая часть в команде "s" сжимает строки, то немного сложнее, как это
Если у части повторного роста растут линии, то немного сложнее, как это
источник
Здесь
/a test/,/Please do not/
рассматривается как блок из (многострочного) текста,c
это команда изменения с последующим новым текстомnot a test \nBe
В случае, если текст для замены очень длинный, я бы предложил ex синтаксис.
источник
Просто немного расширите окно ввода.
Это довольно легко. Помимо стандартной замены; вам нужно только
$!N
,P
иD
здесь.источник
Помимо Perl, общий и удобный подход для многострочного редактирования потоков (и файлов тоже):
Сначала создайте новый UNIQUE разделитель строк, как вам нравится, например
Затем в вашей команде sed (или любом другом инструменте) вы заменяете \ n на $ {S}, например
(awk заменяет разделитель строк ASCII на ваш и наоборот.)
источник
Это небольшая модификация умного ответа xara, чтобы он работал на OS X (я использую 10.10):
Вместо того, чтобы явно использовать
\r
, вы должны использовать$(printf '\r')
.источник
printf '\r'
(илиecho -e '\r'
) все работает правильно, обратите внимание, что вы можете просто использовать синтаксис оболочки$'\r'
для ссылки на экранированные литералы. Например,echo hi$'\n'there
будет эхо новой строки междуhi
иthere
. Точно так же вы можете обернуть всю строку так, чтобы каждая обратная косая черта\
экранировала свой последующий символ:echo $'hi\nthere'
Я хотел добавить несколько строк HTML в файл, используя sed (и закончил здесь). Обычно я бы просто использовал Perl, но я был на коробке с sed, bash и многим другим. Я обнаружил, что если я изменил строку на одну строку и позволил bash / sed интерполировать \ t \ n, все получилось:
Было бы чётче иметь функцию для избежания двойных кавычек и косой черты, но иногда абстракция - это вор времени.
источник
В GNU
sed
есть-z
опция, позволяющая использовать синтаксис, который пытался применить OP. ( справочная страница )Пример:
Помните: если вы используете,
^
и$
теперь они соответствуют началу и концу строк, разделенных символом NUL (не\n
). И, чтобы гарантировать, что совпадения во всех ваших (\n
-отделенных) строках заменены, не забудьте использоватьg
флаг для глобальных замен (напримерs/.../.../g
).Кредиты: @ stéphane-chazelas впервые упомянул -z в комментарии выше.
источник
Sed ломает ввод на новых строках. Он сохраняет только одну строку в цикле.
Поэтому нет способа сопоставить
\n
(новую строку), если пространство шаблона не содержит его.Однако есть способ заставить sed хранить две последовательные строки в пространстве шаблона с помощью цикла:
Добавьте любую обработку, необходимую между N и P (заменив
l
).В этом случае (2 строки):
Или для трех строк:
Это при условии, что такое же количество строк будет заменено.
источник