Я хотел бы выполнить несколько вставок/добавок в одной переносимой команде sed.
В GNU sed я могу сделать что-то вроде:
sed -e '1i hi' -e '$a bye' <(seq 1 10)
Я нашел следующие работы, но я не уверен, что это правильный/лучший способ справиться с этим в sed, совместимом с Posix:
sed --posix '1{x;s/$/hi/;G};//h;${x;s/$/\nbye/}' <(seq 1 10)
--или--
sed --posix '1{x;s/$/hi/;G};${s/$/\nbye/}' <(seq 1 10)
Я не видел, чтобы кто-нибудь действительно обсуждал, как удалить пространство удержания, и предположил - это лучший способ добиться этого во всех sed, совместимых с posix?
Обновление: поскольку \n
на RHS не переносимо, похоже, что он будет состоять из нескольких строк:
sed --posix '1{x;s/$/hi/;G};${s/$/\
> bye/}' <(seq 1 10)
Обновлять: Хорошо, думаю, я нашел способ добавить новую строку, удерживая ее на левой стороне - хотя это довольно некрасиво:
sed '1{G;s/\(.\)\(\n\)/hi\2\1/;};${G;s/\(.\)\(\n\)/\1\2bye/;}' <(seq 1 10)
или это, немного лучше:
sed '1{G;s/\([^\n]*\)\(\n\)/hi\2\1/;};${G;s/\(\n\)/\1bye/;}' <(seq 1 10)
Ответ. Установлено на версии расширения параметров Потонга, выглядит posix-совместимым:
sed --posix $'1i\\hi\n;$a\\bye' <(seq 1 10)
Предпочтителен один вкладыш
Да, я понимаю - согласно sed.sourceforge.io/grabbag/tutorials/sedfaq.txt мне нужно было бы разместить его на нескольких строках, чтобы встроить новую строку в целом.
eval "$(printf 'newline = "\n"')"; sed '...'"${newline}"'...' ...
или sed "$(printf '...\n...')" ...
(необходимо экранировать другие метасимволы строки формата printf)
sed отлично подходит для s/old/new в отдельных строках, для всего остального (т. е. каждый раз, когда вы говорите о «удержании пробела» или используете инструкции sed, отличные от «s», «g» и «p»), просто используйте awk для ясности, простоты, портативности, удобства сопровождения и т. д. и т. п.
@Ed Да, вероятно, его нелегко поддерживать, если вы заблудились в некоторых менее известных командах. Я считаю, что с вставкой/добавлением/удалением справиться довольно легко - HhxgG неплохи, когда вы зацикливаетесь на обмене пространствами удержания/шаблона, но большинство людей с ними не знакомы.
@АдамД. Частично я считаю, что даже если вставка/добавление/удаление и HhxgG не так уж и плохи, как только вы осмысливаете обмен местами удержания/шаблона, их все равно лучше избегать, поскольку одна и та же функциональность проще, понятнее, легче поддерживать/ Enhance и более переносимый в awk, а awk и sed являются обязательными инструментами POSIX, поэтому, если у вас есть sed, у вас также есть awk.
GNUism в первой команде заключается в том, что i
и a
принимают строку, которая будет вставлена в одну строку, тогда как POSIX требует, чтобы они находились в разных строках. Это должно соответствовать:
sed -e '1i \
hi' -e '$a \
bye' <(seq 1 10)
или
sed '1i \
hi
$a \
bye' <(seq 1 10)
Выглядит хорошо, думаю, я пытался удержать это в одной строке. В нескольких строках, возможно, также можно было бы опустить -e sed --posix '1i \ hi $a \ bye' <(seq 1 10)
@АдамД. Пока hi
находится на отдельной строке ($a
на новой строке), да
Да, я так и писал, но комментарии схлопываются. Спасибо, похоже, потребуется многострочная обработка.
К сожалению, MacOS не поддерживает опцию --posix
, но в остальном, похоже, она работает и на Mac.
@tripleee Да, --posix
просто для того, чтобы заставить GNU sed отвергать GNUisms, позвольте мне удалить это...
Могу ли я с уважением предложить вам вместо этого рассмотреть Awk?
awk 'BEGIN { print "hi" } 1; END { print "bye" }' file
У меня тоже было предложение по Perl, но оказалось, что perl -i~ -pe 'BEGIN { print "hi\n"; } END { print "bye\n"; }' poo
не добавляет hi
и bye
к poo
(!)
awk
, наверное, лучше для этого, но я пытаюсь ограничить количество зависимостей - уже имею дело с w/sed в разных местах.
@АдамД. чтобы ограничить зависимости, вам следует везде использовать awk вместо sed, поскольку, как и sed, но в отличие от Perl, Python, Ruby и т. д., awk также является обязательным инструментом POSIX и может делать все, что sed (и grep, seq, tr, wc, и многие другие инструменты обработки текста), как правило, с более простым, понятным, портативным и простым в расширении/поддержании синтаксисом, но обратное неверно.
@ЭдМортон @АдамД. awk
является даже в BusyBox, как я предполагаю на основании требований @AdamD., которые также могут быть индикатором пригодности в среде POSIX/Embedded/ограниченной.
Это может сработать для вас (GNU sed & bash):
sed $'1i\\hi\n$a\\bye' file
или
sed '1G;1s/\(.*\)\(.\)/hi\2\1/;$G;$s/$/bye/' file
или
sed '1h;1s/.*/hi/p;1g;$a\bye' file
или
sed 'H;1h;$!d;s/.*/hi/;G;a\bye' file
или
sed '1{x;s/^/hi/p;x};${p;s/.*/bye/}' file
Спасибо дружище! Первое, это то, что я искал..
Играли в гольф до: sed $'1ihi\n;$abye' <(seq 1 10)
Поскольку перевод строки взят из оболочки, от ;
также можно избавиться. Я поставил двойную обратную косую черту, чтобы сделать решение совместимым с posix.
👍- Да, это, наверное, гольф-макс.
\n
в замену не переносной; это разрешено только в регулярном выражении