Хорошо известно, что такая команда:
cat filename | some_sed_command >filename
стирает имя файла, так как перенаправление вывода, выполняемое перед командой, вызывает усечение имени файла.
Можно решить проблему следующим образом:
cat file | some_sed_command | tee file >/dev/null
но я не уверен, что это сработает в любом случае: что произойдет, если файл (и результат команды sed) очень большой? Как операционная система может избежать перезаписи содержимого, которое до сих пор не прочитано? Я вижу, что есть также команда губки, которая должна работать в любом случае: она "безопаснее", чем тройник?
command-line
bash
tee
VeryHardCoder
источник
источник
Ответы:
Нет .
Скорее всего,
file
будет усечено падение, но нет никаких гарантийcat file | some_sed_command | tee file >/dev/null
, не будет усеченоfile
.Все зависит от того, какая команда обрабатывается первой, в отличие от того, что можно ожидать, команды в конвейере не обрабатываются слева направо . Нет никакой гарантии, какая команда будет выбрана первой, поэтому можно просто думать о ней как о случайно выбранной и никогда не полагаться на то, что оболочка не выберет вызывающую.
Поскольку вероятность того, что нарушающая команда будет выбрана первой между тремя командами, ниже, чем вероятность того, что нарушающая команда будет выбрана первой между двумя командами, менее вероятно, что
file
она будет усечена, но это все же произойдет .script.sh
:Поэтому никогда не используйте что-то подобное
cat file | some_sed_command | tee file >/dev/null
. Используйте,sponge
как предложил Оли.В качестве альтернативы для более ограниченных сред и / или относительно небольших файлов можно использовать строку здесь и подстановку команд, чтобы прочитать файл перед выполнением любой команды:
источник
В
sed
частности, вы можете использовать его-i
аргумент на месте. Он просто сохраняет обратно в файл, который он открыл, например:Если вы хотите сделать что-то более громкое, предполагая, что вы делаете больше, чем
sed
, да, вы можете буферизовать все это с помощьюsponge
(изmoreutils
пакета), что «впитает» весь стандартный ввод перед записью в файл. Это как,tee
но с меньшей функциональностью. Для базового использования, это в значительной степени замена:Это безопаснее? Определенно. Вероятно, он имеет ограничения, поэтому, если вы делаете что-то колоссальное (и не можете редактировать на месте с помощью sed), вы можете захотеть внести изменения во второй файл, а затем
mv
вернуть этот файл к исходному имени файла. Это должно быть атомарно (поэтому все, что зависит от этих файлов, не сломается, если им нужен постоянный доступ).источник
Вы можете использовать Vim в режиме Ex:
%
выбрать все строки!
Команда Runx
Сохранить и выйтиисточник
О, но
sponge
это не единственный вариант; Вам не нужно получатьmoreutils
, чтобы заставить это работать должным образом. Любой механизм будет работать, если он удовлетворяет следующим двум требованиям:Вы видите, хорошо известная проблема, на которую ссылается OP, заключается в том, что оболочка создаст все файлы, необходимые для работы каналов, прежде чем даже начнет выполнять команды в конвейере, поэтому именно оболочка фактически усекает выходной файл (который, к сожалению, также является входным файлом) еще до того, как какая-либо из команд сможет начать выполнение.
Команда
tee
не работает, даже если она удовлетворяет первому требованию, потому что она не удовлетворяет второму требованию: она всегда будет создавать выходной файл сразу после запуска, так что это по сути так же плохо, как создание канала прямо в выходной файл. (На самом деле это еще хуже, потому что его использование вводит недетерминированную случайную задержку перед усечением выходного файла, поэтому вы можете подумать, что он работает, хотя на самом деле это не так.)Итак, все, что нам нужно для решения этой проблемы - это какая-то команда, которая буферизует все свои входные данные перед созданием какого-либо вывода, и которая способна принимать имя выходного файла в качестве параметра, так что нам не нужно передавать его вывод в выходной файл. Одна такая команда
shuf
. Итак, следующее будет выполнять то же самое, чтоsponge
и:Эти
--random-source=/dev/zero
приемы частиshuf
в делать свое дело , не делая перестановку на всех, так что это будет буфер ввода , не изменяя его.источник