2015-05-15 4 views

ответ

3

Есть две проблемы:

  • Вы с помощью GNU Sed синтаксис: в BSD Sed , который является версией, используемой в OSX, -iтребует и аргумента, даже если это пустая строка (чтобы указать, что нет необходимо создать резервную копию), поэтому вы должны использовать -i '' (обратите внимание, что -i'' будет не работать по техническим причинам).

    • См. here для обзора различий между GNU и BSD Sed.
  • Вы не Сопрягать содержимого элемента, as fedorqui points out in his helpful answer.

    • Однако, его регулярное выражение использует GNU синтаксис: квантор \+ (для один или более матчей) является не поддерживается в BSD Сед.
    • Хотя вы можете исправить это легко заменить \+ с POSIX-совместимой \{1,\}, я предлагаю используя расширенный регулярное выражение с -E вместо этого - смотри ниже.

Если вы не должны оставаться по-настоящему POSIX-совместимых (в этом случае вы не можете даже использовать -i), я обычно рекомендуется использовать опцию -E активировать поддержку продлен регулярные выражения:

  • расширенные регулярные выражения являются более мощными и работать гораздо больше, как вы, вероятно, использовали на других языках (особенно в отношении +, ? и |); а именно:
  • синтаксис не станет чище (нет необходимости \ экранирующих символов, таких как (, ), { и }.).

пример: вот исправленный вариант вашей команды с помощью -E:

sed -i '' -E 's/(<string name="myTag">)[^>]+(<\/string>)/\1CHANGED\2/g' ./myfile.xml 

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

  • Вы защищаете сценарий от возможной нежелательной интерпретации (расширений) переднего плана оболочкой.
  • Вам не обязательно \ -escape " экземпляров.
+1

очень понятно, спасибо за это! –

+1

@AlexDarsonik вам следует подумать о принятии ответа тогда! – fedorqui

3

Вы не соответствуете по количеству меток между <string и </string>. Используйте, например [^<]* сослаться на все вплоть до < найден:

$ sed -e 's/\(<string name="myTag">\)[^<]*\(<\/string>\)/\1CHANGED\2/g' file 
<string name="myTag">CHANGED</string> 

По предложению Дипак, вы можете избежать написания CHANGED если не текст в <string> и </string> тегов. Если да, то вы можете сказать [^<]+, чтобы убедиться, что по крайней мере один символ найден:

$ cat a 
<string name="myTag">CHANGEME</string> 
<string name="myTag"></string> 
$ sed -e 's/\(<string name="myTag">\)[^<]\+\(<\/string>\)/\1CHANGED\2/g' a 
<string name="myTag">CHANGED</string> 
<string name="myTag"></string> 
1

Это должно быть комментарий, но так как я не получил привилегию, я вывешиваю здесь

Код предложил по Fedorqui отлично работает и меняет Changeme в ИЗМЕНЕНО, но и, если нет ничего между тегами будет вставить ИЗМЕНЕНО

Вы можете изменить код, как бела вл в случае требование оставить пустой тег как пустые:

sed 's/\(<string name="myTag">\)[^<].*\(<\/string>\)/\1CHANGED\2/g'

ИЛИ

sed 's/\(<string name="myTag">\)..*\(<\/string>\)/\1CHANGED\2/g' file

В случае 1 он ищет <string name="myTag"> после чего-то, который не начинается с < затем 0 или более случаев и заменяет их ИЗМЕНИТЬ. Случай 2 ищет <string name="myTag"> следует, по меньшей мере, один символ и заменяет то же самое с изменившихся

+0

Это хороший момент в целом, но оба '[^ <]. *' И '.. *' потенциально слишком жадные, поскольку они будут соответствовать слишком много, если строка содержит более одного '' instance ; см., что происходит с ' foo другой '', например. Чтобы исправить это для _BSD_ Sed (в OSX), вам придется использовать либо '[^ <] [^ <] *', либо, предпочтительно, '[^ <] \ {1, \}'. – mklement0

Смежные вопросы