С bash
оболочкой, в файле со строками, подобными следующим
first "line"
<second>line and so on
Я хотел бы, чтобы заменить один или несколько вхождений "line"\n<second>
с other characters
и получить каждый раз , когда :
first other characters line and so on
Поэтому я должен заменить строку как специальными символами, такими как "
и, так <
и символом новой строки.
После поиска между другими ответами я обнаружил, что sed
может принимать переводы строк в правой части команды (так, в other characters
строке), но не в левой.
Есть ли способ (проще, чем этот ) получить этот результат с помощью sed
или grep
?
text-processing
sed
grep
newlines
BowPark
источник
источник
\n
заявление ewline вы делаете почему я спрашиваю. люди редко спрашивают, могут ли они сделать тоs//\n/
же самое, что и вы с GNUsed
, хотя большинство другихsed
отклонят этот побег с правой стороны. тем не менее,\n
escape будет работать слева в любом POSIX,sed
и вы можете переносить их, какy/c/\n/
будто это будет иметь тот же эффект, чтоs/c/\n/g
и не всегда так полезно.Ответы:
Три разные
sed
команды:Все они
s///
основаны на основной команде ubstitution:Они также все стараются позаботиться об обработке последней строки, так как
sed
s имеют тенденцию различаться по своему выводу в крайних случаях. Это значение$!
адреса, соответствующего каждой строке, которая!
не является$
последней.Все они также используют команду
N
ext, чтобы добавить следующую строку ввода к\n
пробелу шаблона после символа ewline. Любой, кто занималсяsed
какое-то время, научится полагаться на\n
персонажа ewline - потому что единственный способ получить его - это явно поместить его туда.Все три делают некоторую попытку прочитать как можно меньше входных данных, прежде чем предпринимать какие-либо действия -
sed
действуют так быстро, как это возможно, и не нужно читать весь входной файл перед этим.Хотя они делают все
N
, они все три отличаются по своим методам рекурсии.Первая команда
Первая команда использует очень простой
N;P;D
цикл. Эти три команды встроены в любую POSIX-совместимую системуsed
и прекрасно дополняют друг друга.N
- как уже упоминалось, добавляетN
строку ввода ext в шаблонное пространство после вставленного\n
разделителя ewline.P
- какp
; онP
запечатлевает шаблонное пространство - но только до первого встречающегося\n
символа ewline. И так, с учетом следующего ввода / команды:printf %s\\n one two | sed '$!N;P;d'
sed
P
звонит только один . Тем не менее, с ...D
- какd
; онD
выбирает шаблонное пространство и начинает другой цикл строки. В отличие отd
,D
удаляет только до первой\n
встречной линии в шаблонном пространстве. Если после\n
символа ewline в шаблонном пространстве больше,sed
начинается следующий цикл строки с тем, что остается. Еслиd
в предыдущем примере было заменено наD
, например,sed
будетP
набирать как один, так и два .Эта команда повторяется только для строк, которые не соответствуют
s///
выражению ubstitution. Посколькуs///
ubstitution удаляет\n
ewline, добавленный с помощьюN
, приsed
D
выборке шаблон-пространства ничего не остается .Можно выполнить тесты для применения
P
и / илиD
выборочно, но есть и другие команды, которые лучше подходят для этой стратегии. Поскольку рекурсия реализована для обработки последовательных строк , которые соответствуют только части правила замены, последовательные последовательности линий , соответствующих оба конца наs///
ubstitution не работают хорошо .:Учитывая этот вклад:
... это печатает ...
Это, однако, обрабатывать
...просто хорошо.
Вторая команда
Эта команда очень похожа на третью. Оба используют ярлык
:b
ранчо /t
est (как также продемонстрировано в ответе Джозефа Р. здесь ) и возвращаются к нему при определенных условиях.-e :n -e
- переносимыеsed
сценарии разграничивают определение:
метки либо с помощью\n
ewline, либо с помощью нового встроенного-e
оператора xecution.:n
- определяет метку с именемn
. Это может быть возвращено в любое время с помощьюbn
илиtn
.tn
- командаt
est возвращается к указанной метке (или, если она не указана , выходит из сценария для текущего цикла строки), еслиs///
возникла какая-либо замена, поскольку либо метка была определена, либо поскольку она в последний раз называласьt
успешной проверкой.В этой команде рекурсия происходит для совпадающих строк. Если
sed
успешно заменить шаблон с другими символами ,sed
возвращается к:n
метке и пытается снова. Еслиs///
замена не выполняется,sed
автоматически печатается шаблонное пространство и начинается следующий цикл строки.Это имеет тенденцию обрабатывать последовательные последовательности лучше. Там, где последний провалился, это печатает:
Третья команда
Как уже упоминалось, логика здесь очень похожа на последнюю, но тест более явный.
/"$/bn
- этоsed
тест. Поскольку командаb
ранчо является функцией этого адреса,sed
онаb
вернется на ранчо только:n
после добавления\n
ewline, и пространство шаблона все еще заканчивается"
двойной кавычкой .Между
N
иb
как можно меньше делается - таким образомsed
можно очень быстро собрать ровно столько информации, сколько необходимо, чтобы гарантировать, что следующая строка не может соответствовать вашему правилу. Вs///
ubstitution отличается здесь в том , что она используетg
ЛОБАЛЬНЫЙ флаг - и поэтому он будет делать все необходимые замены сразу. При одинаковом вводе эта команда выводит идентично последнему.источник
DATA
и как вы получаете ввод текста?<<\DATA\ntext input\nDATA\n
запекается, но это только текст, передаваемыйsed
оболочкой в документе здесь . Это будет работать так же, какsed 'script' filename
илиprocess that writes to stdout | sed 'script'
. Это помогает?D
каждой модифицированной строки двойная? (Вы использовали это по мере необходимости; возможно, я неsed
очень хорошо знаю )D
потому что вD
противном случаеD
выводится из вывода то, что вы теперь видите удвоенным. Я только что сделал правку - и я могу расширить это также в ближайшее время.D
вещи.Что ж, я могу придумать пару простых способов, но ни один из
grep
них не включает (которые в любом случае не делают подстановок) илиsed
.Perl
Для того, чтобы заменить каждое вхождение
"line"\n<second>
сother characters
, использованием:Или, чтобы рассматривать несколько последовательных вхождений
"line"\n<second>
как одно и заменить все из них однимother characters
, используйте:Пример:
-00
Приводит к Perl , чтобы прочитать файл в режиме «пункт» , который означает , что «линия» определяется путем\n\n
вместо\n
, по сути, каждый пункт рассматриваются как линия. Таким образом, подстановка совпадает с новой строкой.AWK
По той же самой основной идее мы устанавливаем разделитель записей (
RS
), чтобы он\n\n
хранил весь файл, затем разделитель выходных записей - ничто (в противном случае выводится дополнительная новая строка), а затем используемsub()
функцию для выполнения замены.источник
awk
должна бытьprint;}' file
. Мне нужно избегать Perl и предпочтительно использоватьsed
, в любом случае вы предложили хорошие альтернативы.прочитайте весь файл и сделайте глобальную замену:
источник
${cmds}
это специфично для GNU - большинству другихsed
требуется\n
ewline или-e
разрыв междуp
и}
. Вы можете полностью избежать скобок - и переносимо - и даже не вставлять дополнительный\n
символ ewline в первую строку, например:sed 'H;1h;$!d;x;s/"line"\n<second>/other characters /g'
sed -n '1{h;n};H; ${x; s/"line"\n<second>/other characters /g; p}'
символ новой строки: - однако это становится неосуществимым.Вот вариант ответа glenn, который будет работать, если у вас есть несколько последовательных вхождений (работает
sed
только с GNU ):Это
:x
просто метка для ветвления. По сути, это то, что он проверяет строку после подстановки и, если она все еще совпадает"line"
, возвращается к:x
метке (вот чтоbx
делает), добавляет еще одну строку в буфер и начинает обрабатывать ее.источник
sed
который обрабатывает не-POSIX-метки достаточно далеко, чтобы принять пробел в качестве разделителя для объявления метки. Тем не менее, вы должны отметить, что любой другойsed
там потерпит неудачу - и потерпит неудачуN
. GNUsed
нарушает правила POSIX для печати пространства шаблонов перед выходомN
в последней строке, но POSIX дает понять, что еслиN
команда читается в последней строке, ничего печатать не следует.v
команде GNU, которая разбивается на части,sed
но не работает в GNU версии 4 и выше.sed -e :x -e '/"line"/{$!N' -e '};s/"line"\n<second>/other characters/;/"line"/bx'
.