Почему перенаправление вывода файла на себя создает пустой файл?
Заявлено в Bash, почему
less foo.txt > foo.txt
и
fold foo.txt > foo.txt
производить пустой foo.txt
? Поскольку при добавлении, например, less eggs.py >> eggs.py
создается две копии текста eggs.py
, можно ожидать, что при перезаписи будет получена одна копия текста.
Заметьте, я не говорю, что это ошибка, это скорее указатель на что-то глубокое в Unix.
bash
unix
unix-utils
seewalker
источник
источник
Ответы:
При использовании
>
файл открывается в режиме усечения, поэтому его содержимое удаляется до того, как команда попытается его прочитать.При использовании
>>
файл открывается в режиме добавления, поэтому существующие данные сохраняются. Однако в этом случае все еще довольно рискованно использовать один и тот же файл для ввода и вывода. Если файл достаточно велик, чтобы не соответствовать размеру входного буфера чтения, его размер может увеличиваться до бесконечности, пока файловая система не заполнится (или не будет достигнута квота на диске).Если вы хотите использовать файл как для ввода, так и для вывода с командой, которая не поддерживает модификацию места, вы можете использовать несколько обходных путей:
Используйте промежуточный файл и перезапишите исходный файл, когда это будет сделано, и только в том случае, если при запуске утилиты не возникло ошибок (это самый безопасный и распространенный способ).
Избегайте промежуточного файла за счет возможной частичной или полной потери данных в случае ошибки или прерывания. В этом примере содержимое
foo.txt
передается в качестве входных данных в подоболочку (внутри скобок) перед удалением файла. Предыдущий инод остается активным, поскольку подоболочка сохраняет его открытым во время чтения данных. Файл, написанный внутренней утилитой (здесьfold
) с тем же именем (foo.txt
) указывает на другой индекс, потому что старая запись каталога была технически удалена, во время процесса есть два разных «файла» с одинаковыми именами. Когда подоболочка заканчивается, старый инод освобождается и его данные теряются. Будьте осторожны, чтобы убедиться, что у вас достаточно места для временного хранения старого и нового файлов одновременно, иначе вы потеряете данные.источник
sponge
от moreutils тоже может помочь.fold foo.txt | sponge foo.txt
- илиfold foo.txt | sponge !$
должен также сделать.Файл открывается для записи оболочкой, прежде чем приложение сможет его прочитать. Открытие файла для записи усекает его.
источник
В bash оператор перенаправления потока
... > foo.txt
очищаетсяfoo.txt
перед вычислением левого операнда .Можно использовать подстановку команды и вывести ее результат в качестве обходного пути. Это решение требует меньше дополнительных символов, чем в других ответах:
Осторожно: эта команда не сохраняет никаких новых символов перевода строки в
foo.txt
. Посмотрите в разделе комментариев ниже для получения дополнительной информацииЗдесь подоболочка
$(...)
оценивается перед оператором перенаправления потока>
, следовательно, сохраняется информация.источник
tmp=$(cmd; printf q); printf '%s' "${tmp%q}"
. Но вы пропустили еще одну проблему с этим ответом: он говорит «subshell», когда он означает «подстановка команд». Да, подстановки команд обычно являются подоболочками, но не наоборот, и подоболочки, как правило, не помогают в этой проблеме.