Используя sed для нахождения и заменения сложной строки (предпочтительно с regex)

Да, это возможно. При использовании этих опций значение по умолчанию должно только распечатать каждую строку. Это является очень подробным, и не, что Вы хотите.

diff --unchanged-line-format=""

устранит строки, которые неизменны, поэтому теперь, только старые и новые линии продолжаются.

diff --unchanged-line-format="" --new-line-format=":%dn: %L"

теперь покажет новые строки, снабженные префиксом :<linenumber>: и пространство, но все еще печатают старые строки. Принятие Вас хочет устранить их,

diff --unchanged-line-format="" --old-line-format="" --new-line-format=":%dn: %L"

Если Вы хотите, чтобы старые строки, а не новые были распечатаны, подкачайте их вокруг.

90
01.05.2017, 03:04
7 ответов
sed -i -E "s/(<username>.+)name(.+<\/username>)/\1something\2/" file.xml

Это, я думаю, что Вы ищете.

Объяснение:

  • круглые скобки в первой части определяют группы (строки на самом деле), который может быть снова использован во второй части
  • \1, \2, и т.д. во второй части ссылки на i-th группу, полученную в первой части (нумерация запускается с 1),
  • -E включает расширенные регулярные выражения (необходимый для + и группировка).
168
27.01.2020, 19:30
  • 1
    +1 для-E опции –  slackmart 08.06.2013, 01:03
  • 2
    это оставляет позади файл резервной копии с именем (original name) + "-E". –  Display Name 13.11.2015, 07:32
  • 3
    На OSX я добираюсь 'sed: 1: "s / (<имя пользователя>. +) имя (. +...": \1 не определенный в РЕ'. Я вставил точный пример от этого вопроса в файл. затем я выполнил команду из этого ответа на том файле. Возможно, OSX имеет другой синтаксис? –  deweydb 21.01.2017, 07:52
  • 4
    Версия гну sed поддерживает "-E" параметр, но не официальная. Это даже не упоминается в странице справочника. Если Вы хотите использовать расширенный regex, необходимо использовать "-r" параметр вместо этого. –  Ikem Krueger 19.09.2017, 20:39
  • 5
    @deweydb Согласно этому ответу, необходимо использовать \( и \) вместо ( и ). –  Zhang Buzz 12.11.2017, 15:56
sed -e '/username/s/CDATA\[name\]/CDATA\[something\]/' \
-e '/password/s/CDATA\[password\]/CDATA\[somethingelse\]/' \
-e '/dbname/s/CDATA\[name\]/CDATA\[somethingdifferent\]/' file.txt

/username/ перед s говорит sed только работать над строками, содержащими строку 'имя пользователя'.

14
27.01.2020, 19:30
  • 1
    , Изящной, эффективной и отлично соответствованной случай. +1 –  lgeorget 08.06.2013, 01:08

Если sed не трудное требование, лучше используйте специальный инструмент вместо этого.

Если Ваш файл является допустимым XML (не только те 3 выглядящих словно XML тега), то можно использовать XMLStarlet:

xml ed -P -O -L \
  -u '//username/text()' -v 'something' \
  -u '//password/text()' -v 'somethingelse' \
  -u '//dbname/text()' -v 'somethingdifferent' file.xml

Вышеупомянутое будет также работать в ситуациях, которые было бы трудно решить с регулярными выражениями:

  • Может заменить значения тегов, не указывая их текущие значения.
  • Может заменить значения, даже если их просто оставляют и не включают в CDATA.
  • Может заменить значения, даже если теги имеют атрибуты.
  • Может легко заменить просто случаи тегов, если существуют несколько с тем же именем.
  • Может отформатировать измененный XML путем расположения с отступом его.

Краткая демонстрация вышеупомянутого:

bash-4.2$ cat file.xml
<sith>
<master>
<username><![CDATA[name]]></username>
</master>
<apprentice>
<username><![CDATA[name]]></username>
<password>password</password>
<dbname foo="bar"><![CDATA[name]]></dbname>
</apprentice>
</sith>

bash-4.2$ xml ed -O -u '//apprentice/username/text()' -v 'something' -u '//password/text()' -v 'somethingelse' -u '//dbname/text()' -v 'somethingdifferent' file.xml
<sith>
  <master>
    <username><![CDATA[name]]></username>
  </master>
  <apprentice>
    <username><![CDATA[something]]></username>
    <password>somethingelse</password>
    <dbname foo="bar"><![CDATA[somethingdifferent]]></dbname>
  </apprentice>
</sith>
6
27.01.2020, 19:30

Необходимо заключить в кавычки \[.*^$/ в части регулярного выражения s команда и \&/ в сменной детали, плюс новые строки. Регулярное выражение является основным регулярным выражением, и кроме того необходимо заключить разделитель в кавычки для s команда.

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

sed -e 's~<username><!\[CDATA\[name\]\]></username>~<username><![CDATA[something]]></username>~'

Можно использовать группы, чтобы не повторить некоторые части в тексте замены и размещать вариацию на эти части.

sed -e 's~\(<username><!\[[A-Z]*\[\)name\(\]\]></username>\)~\1something\2~'

sed -e 's~\(<username>.*[^A-Za-z]\[\)name\([^A-Za-z].*</username>\)~\1something\2~'
3
27.01.2020, 19:30

Для замены слово "имени" с "чем-то" слово используйте:

sed "s/\(<username><\!\[[A-Z]*\[\)name\]/\1something/g" file.xml

Это собирается заменить все случаи указанного слова.

До сих пор все производится к стандартному выводу, можно использовать:

sed "s/\(<username><\!\[[A-Z]*\[\)name\]/\1something/g" file.xml > anotherfile.xml

сохранить изменения в другом файле.

1
27.01.2020, 19:30
$ sed -e '1s/name/something/2' \
      -e '3s/name/somethingdifferent/2' \
      -e 's/password/somethingelse/2' sample.xml

Вы можете просто использовать адреса, как в числе перед "s", которое указывает номер строки.

Также число в конце указывает sed заменить второе совпадение вместо замены первого совпадения.

5
27.01.2020, 19:30
Usage: sed [OPTION]... {script-only-if-no-other-script} [input-file]...

    -r, --regexp-extended
             use extended regular expressions in the script.

чтобы заменить значение в файле свойств

sed -i -r 's/MAIL\=(.+)/MAIL\=user@mymail.com/' etc/service.properties 
0
27.01.2020, 19:30

Теги

Похожие вопросы