Почему "sed -n -i" удаляет существующее содержимое файла?
Запуск Fedora 25 серверной версии. sed --version
дает мне sed (GNU sed) 4.2.2
наряду с обычным авторским правом и контактной информацией. Я создал текстовый файл sudo vi ./potential_sed_bug
, Vi показывает содержимое этого файла (с :set list
включен) как:
don't$
delete$
me$
please$
Затем я запускаю следующую команду:
sudo sed -n -i.bak /please/a\testing ./potential_sed_bug
Прежде чем мы обсудим результаты; вот что говорит man-страница sed:
-n, --quiet, --silent подавить автоматическую печать пространства шаблона
а также
-i[SUFFIX], --in-place[=SUFFIX] редактировать файлы на месте (делает резервную копию, если расширение предоставлено). Режим работы по умолчанию - разорвать символические и жесткие ссылки. Это можно изменить с помощью --follow-symlinks и --copy.
Я также посмотрел другие ссылки на команды sed, чтобы узнать, как добавить с помощью sed. Основываясь на моем понимании из исследования, которое я сделал; итоговое содержимое файла должно быть:
don't
delete
me
please
testing
Тем не менее, работает sudo cat ./potential_sed_bug
дает мне следующий вывод:
testing
В свете этого несоответствия, мое понимание команды, которую я выполнил неправильно, или есть ошибка с sed/ environment?
1 ответ
ТЛ; др
Не использовать
-n
с-i
: если вы не используете явные команды вывода в вашемsed
скрипт, ничего не будет записано в ваш файл.С помощью
-i
не производит вывод stdout (терминал), так что вам не нужно ничего делать, чтобы ваша команда работала тихо.
По умолчанию, sed
автоматически печатает (возможно измененные) входные строки независимо от того, является ли его целевым объектом вывода, подразумеваемым или явным образом заданным: по умолчанию, в stdout (терминал, если не перенаправлен); с -i
, во временный файл, который в конечном итоге заменяет входной файл.
В обоих случаях -n
подавляет эту автоматическую печать, так что - если вы не используете явные функции вывода, такие как p
или, в вашем случае, a
- ничего не выводится на стандартный вывод / записывается во временный файл.
- Обратите внимание, что автоматическая печать применяется к так называемому пространству шаблона, где хранится (возможно, измененный) ввод; явные выходные функции, такие как
p
,a
,i
а такжеc
не печатают в пространство шаблона (для возможной последующей модификации), они печатают непосредственно в целевой поток / файл, поэтомуa\testing
был в состоянии произвести продукцию, несмотря на использование-n
,
Обратите внимание, что с -i
, sed
Неявные команды печати / явного вывода печатают только во временный файл, а не на стандартный вывод, поэтому команда использует -i
неизменно тихий по отношению к выводу stdout (терминала) - вам ничего не нужно делать.
Чтобы привести конкретный пример (GNU sed
синтаксис).
Так как использование -i
Случайный вопрос, я для простоты опустил. Обратите внимание, что -i
сначала печатается во временный файл, который по завершении заменяет оригинал. Это связано с подводными камнями, в частности, с потенциальным разрушением символических ссылок; см. нижнюю половину этого моего ответа.
# Print input (by default), and append literal 'testing' after
# lines that contain 'please'.
$ sed '/please/ a testing' <<<$'yes\nplease\nmore'
yes
please
testing
more
# Adding `-n` suppresses the default printing, so only `testing` is printed.
# Note that the sequence of processing is exactly the same as without `-n`:
# If and when a line with 'please' is found, 'testing' is appended *at that time*.
$ sed -n '/please/ a testing' <<<$'yes\nplease\nmore'
testing
# Adding an unconditional `p` (print) call undoes the effect of `-n`.
$ sed -n 'p; /please/ a testing' <<<$'yes\nplease\nmore'
yes
please
testing
more