Найти и заменить в файле и перезаписать файл не работает, он очищает файл

Я хотел бы запустить поиск и заменить файл 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 - это содержимое файла, и поиск и замена выполнены.

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

Ответ 1

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

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

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

Без .bak команда выйдет из строя на некоторых платформах, таких как Mac OSX.

Ответ 2

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

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

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

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

Ответ 3

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

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

Ответ 4

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

sed -i bak -e s/STRING_TO_REPLACE/REPLACE_WITH/g index.html

Ответ 5

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

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

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

Ответ 6

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

Ответ 7

sed -i.bak "s#https.*\.com#$pub_url#g" MyHTMLFile.html

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

Это работает!

Ответ 8

Предупреждение: это опасный метод! Он использует буферы ввода/вывода в 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 откроет файл для записи, и он будет очищен. Однако, если вы включите буферизацию всегда, вторая версия тоже будет работать.

Ответ 9

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

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

Ответ 10

И ответ ed:

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

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

Ответ 11

Вы можете использовать Vim в режиме Ex:

ex -sc '%s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g|x' index.html
  • % выберите все строки

  • x сохранить и закрыть

Ответ 12

Я искал вариант, где я могу определить диапазон строк и найти ответ. Например, я хочу изменить host1 на host2 из строки 36-57.

sed '36,57 s/host1/host2/g' myfile.txt > myfile1.txt

Вы можете использовать опцию gi, чтобы игнорировать случай символа.

sed '30,40 s/version/story/gi' myfile.txt > myfile1.txt

Ответ 13

При всем должном уважении к приведенным выше правильным ответам всегда рекомендуется использовать сценарии "сухого запуска", так что вы не повредите свой файл и не должны начинать с нуля.

Просто попробуйте script вывести вывод в командную строку вместо записи в файл, например:

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

ИЛИ

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

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