Почему перенаправление вывода файла на себя создает пустой файл?

Почему перенаправление вывода файла на себя создает пустой файл?

Заявлено в Bash, почему

less foo.txt > foo.txt

а также

fold foo.txt > foo.txt

производить пустой foo.txt? Так как приложение, такое как less eggs.py >> eggs.py производит две копии текста в eggs.pyможно было бы ожидать, что перезапись произведет одну копию текста.

Заметьте, я не говорю, что это ошибка, это скорее указатель на что-то глубокое в Unix.

3 ответа

Когда вы используете >файл открывается в режиме усечения, поэтому его содержимое удаляется до того, как команда попытается его прочитать.

Когда вы используете >>, файл открывается в режиме добавления, поэтому существующие данные сохраняются. Однако в этом случае все еще довольно рискованно использовать один и тот же файл для ввода и вывода. Если файл достаточно велик, чтобы не соответствовать размеру входного буфера чтения, его размер может увеличиваться до бесконечности, пока файловая система не заполнится (или не будет достигнута квота на диске).

Если вы хотите использовать файл как для ввода, так и для вывода с командой, которая не поддерживает модификацию места, вы можете использовать несколько обходных путей:

  • Используйте промежуточный файл и перезапишите исходный файл, когда это будет сделано, и только в том случае, если при запуске утилиты не возникло ошибок (это самый безопасный и распространенный способ).

    fold foo.txt > fold.txt.$$ && mv fold.txt.$$ foo.txt
    
  • Избегайте промежуточного файла за счет возможной частичной или полной потери данных в случае ошибки или прерывания. В этом примере содержимое foo.txt передаются в качестве входных данных в подоболочку (внутри скобок) перед удалением файла. Предыдущий инод остается активным, поскольку подоболочка сохраняет его открытым во время чтения данных. Файл, написанный внутренней утилитой (здесь fold) имея то же имя (foo.txt) указывает на другой индекс, потому что старая запись каталога была технически удалена, во время процесса есть два разных "файла" с одинаковыми именами. Когда подоболочка заканчивается, старый инод освобождается и его данные теряются. Будьте осторожны, чтобы убедиться, что у вас достаточно места для временного хранения старого и нового файлов одновременно, иначе вы потеряете данные.

    (rm foo.txt; fold > foo.txt) < foo.txt
    

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

В bash оператор перенаправления потока ... > foo.txt порожняк foo.txt перед оценкой левого операнда.

Можно использовать подстановку команды и вывести ее результат в качестве обходного пути. Это решение требует меньше дополнительных символов, чем в других ответах:

printf "%s\n" "$(less foo.txt)" > foo.txt

Осторожно: эта команда не сохраняет никаких новых символов перевода строки в foo.txt , Посмотрите в разделе комментариев ниже для получения дополнительной информации

Здесь, скорлупа $(...) оценивается перед оператором перенаправления потока > отсюда и сохранение информации.

Другие вопросы по тегам