Найти и заменить в файле и перезаписать файл не работает, он очищает файл - PullRequest
572 голосов
/ 02 марта 2011

Я хотел бы запустить поиск и замену файла HTML через командную строку.

Моя команда выглядит примерно так:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html > index.html

Когда я запускаю это и смотрю навпоследствии файл пуст.Он удалил содержимое моего файла.

Когда я запустил это после восстановления файла снова:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

stdout - это содержимое файла, а поиск и заменабыл казнен.

Почему это происходит?

Ответы [ 13 ]

881 голосов
/ 02 марта 2011

Когда shell видит > index.html в командной строке, он открывает файл index.html для записи , стирая все его предыдущее содержимое.

ToЧтобы исправить это, вам нужно передать параметр -i в sed, чтобы сделать изменения встроенными и создать резервную копию исходного файла, прежде чем он внесет изменения на месте:

sed -i.bak s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

Без .bakкоманда не будет работать на некоторых платформах, таких как Mac OSX.

201 голосов
/ 03 марта 2011

Альтернативный, полезный шаблон:

sed -e 'script script' index.html > index.html.tmp && mv index.html.tmp index.html

Это имеет почти тот же эффект, без использования опции -i, и дополнительно означает, что, если сценарий sed завершается ошибкой по какой-то причине, входной файл не засоряется. Кроме того, если редактирование прошло успешно, резервной копии не осталось. Этот вид идиомы может быть полезен в Makefiles.

Довольно много seds имеют опцию -i, но не все; posix sed - это тот, который не делает. Поэтому, если вы стремитесь к мобильности, этого лучше избегать.

86 голосов
/ 10 августа 2013
sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' index.html

Это делает глобальную замену на месте в файле index.html.Заключение строки в кавычки предотвращает проблемы с пробелами в запросе и замене.

56 голосов
/ 02 марта 2011

используйте опцию sed -i, например,

sed -i bak -e s/STRING_TO_REPLACE/REPLACE_WITH/g index.html
18 голосов
/ 21 июня 2013

Чтобы изменить несколько файлов (и сохранить резервную копию каждого как * .bak):

perl -p -i -e "s/\|/x/g" *  

возьмет все файлы в каталоге и заменит | на x это называется «Perl пирог» (просто как пирог)

14 голосов
/ 02 марта 2011

Вы должны попробовать использовать опцию -i для редактирования на месте.

6 голосов
/ 09 октября 2015
sed -i.bak "s#https.*\.com#$pub_url#g" MyHTMLFile.html

Если у вас есть ссылка для добавления, попробуйте это. Найдите URL-адрес, как указано выше (начиная с https и заканчивая здесь.com), и замените его строкой URL-адреса. Я использовал переменную $pub_url здесь. s здесь означает поиск, а g означает глобальную замену.

Работает!

5 голосов
/ 17 июля 2013

Предупреждение: это опасный метод! Он использует буферы ввода / вывода в linux и с определенными параметрами буферизации ему удается работать с небольшими файлами. Это интересное любопытство. Но не используйте это для реальной ситуации!

Помимо опции -i sed Вы можете использовать утилиту tee .

С man:

tee - чтение со стандартного ввода и запись в стандартный вывод и файлы

Итак, решение будет:

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee | tee index.html

- здесь tee повторяется, чтобы убедиться, что конвейер буферизован. Затем все команды в конвейере блокируются, пока они не получат некоторый ввод для работы. Каждая команда в конвейере начинается, когда вышестоящие команды записывают 1 буфер байтов (размер определяется где-то ) на вход команды. Поэтому последняя команда tee index.html, которая открывает файл для записи и, следовательно, очищает его, выполняется после завершения восходящего конвейера и вывода в буфер внутри конвейера.

Скорее всего, следующее не сработает:

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee index.html

- он будет запускать обе команды конвейера одновременно без какой-либо блокировки. (Без блокировки конвейер должен передавать байты строка за строкой, а не буфер за буфером. То же, что и при запуске cat | sed s/bar/GGG/. Без блокировки он более интерактивен и обычно конвейеры всего из 2 команд выполняются без буферизации и блокировки. Более длинные конвейеры буферизуются. ) tee index.html откроет файл для записи и будет очищен. Однако, если вы включите буферизацию всегда, вторая версия тоже будет работать.

4 голосов
/ 30 июля 2015

Проблема с командой

sed 'code' file > file

заключается в том, что file обрезается оболочкой до того, как sed действительно ее обработает. В результате вы получите пустой файл.

Единственный способ сделать это - использовать -i для редактирования на месте, как предлагали другие ответы. Однако это не всегда то, что вы хотите. -i создаст временный файл, который затем будет использован для замены исходного файла. Это проблематично, если в вашем исходном файле была ссылка (ссылка будет заменена обычным файлом). Если вам нужно сохранить ссылки, вы можете использовать временную переменную для хранения вывода sed перед записью его обратно в файл, например:

tmp=$(sed 'code' file); echo -n "$tmp" > file

Еще лучше, используйте printf вместо echo, поскольку echo может обрабатывать \\ как \ в некоторых оболочках (например, тире):

tmp=$(sed 'code' file); printf "%s" "$tmp" > file
3 голосов
/ 28 июня 2011

И ответ ed:

printf "%s\n" '1,$s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' w q | ed index.html

Чтобы повторить ответ codaddict , оболочка обрабатывает перенаправление first , стирая файл "input.html", а затем shell вызывает Команда "sed" передает ему пустой файл.

...