Как заменить два шаблона на месте с помощью `sed`?

409
monster

Я использую sedкоманду, чтобы изменить, <active>trueчтобы <active>falseв файле XML. Теперь, если я использую

sed 's/<active>true/<active>false/g' file.xml > file.xml 

это полностью стирает содержимое моего файла. При использовании >>вместо >, он добавляет вывод в конце, как ожидается.

  1. Как добиться того, что я хочу сделать?
  2. Почему >так странно себя ведет?
  3. Что я на самом деле нужно сделать, это изменить, <active>trueчтобы, <active>falseесли <active>trueприсутствует и наоборот, если <active>falseприсутствует в файле. Есть ли какая-то команда, которая может это сделать, или мне нужно написать сценарий с if-elseмоим первоначальным планом?
0
2: [Этот ответ] (https://unix.stackexchange.com/a/79039/108618). Расследовать `sed -i`. Kamil Maciorowski 5 лет назад 1
@KamilMaciorowski, так что вкратце `file.xml` был обрезан перед выполнением` sed`? monster 5 лет назад 0
Да. В Linux есть общий инструмент, позволяющий этого избежать: [`sponge`] (https://linux.die.net/man/1/sponge). Kamil Maciorowski 5 лет назад 1
спасибо, `sed -i` решил вопросы 2 и 1, хотя при использовании губки выдал ошибку` команда не найдена` monster 5 лет назад 0
В Debian или Ubuntu `sponge` является частью пакета` moreutils`, который не устанавливается по умолчанию. Я думаю, что в других дистрибутивах ситуация похожа. Kamil Maciorowski 5 лет назад 0

1 ответ на вопрос

1
Kamil Maciorowski

Поведение >объясняется в этом ответе Unix & Linux SE . Пример есть cat test.txt > test.txtи объяснение:

Первое, что происходит, это открытие bash test.txt, которое усекает файл. Теперь он пуст, до того, catкак выполняется с test.txtаргументом.

Вы sed '…' file.xml > file.xmlзапускаете то же самое поведение.

Довольно простое решение с одним sed:

sed -i 's/<active>true/<active>DUMMY/g s/<active>false/<active>true/g s/<active>DUMMY/<active>false/g' file.xml 

-iВариант решает проблему с файлом усекается. Команда превращается <active>trueв <active>falseи наоборот. Обратите внимание, вы не можете использовать только

s/<active>true/<active>false/g;s/<active>false/<active>true/g 

потому что вторая часть не может сказать, является ли какой-либо falseоригинал falseили оригинал trueтолько что превращенным false. Это вызывает каждое совпадение trueили falseзаканчивается как true. По этой причине я использовал временную DUMMYзамену. Может быть, есть лучший способ сделать это, я пока не знаю.

Единственное условие - строка <active>DUMMYне может появиться в исходном файле. Если это может появиться, используйте другую фиктивную строку, которая точно не появляется.

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