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

3555
seewalker

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

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

less foo.txt > foo.txt 

а также

fold foo.txt > foo.txt 

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

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

17

2 ответа на вопрос

18
jlliagre

When you use >, the file is opened in truncation mode so its contents are removed before the command attempts to read it.

When you use >>, the file is opened in append mode so the existing data is preserved. It is however still pretty risky to use the same file as input and output in this case. If the file is large enough not to fit the read input buffer size, its size might grow indefinitely until the file system is full (or your disk quota is reached).

Should you want to use a file both as input and output with a command that doesn't support in place modification, you can use a couple of workarounds:

  • Use an intermediary file and overwrite the original one when done and only if no error occurred while running the utility (this is the safest and more common way).

    fold foo.txt > fold.txt.$$ && mv fold.txt.$$ foo.txt 
  • Avoid the intermediary file at the expense of a potential partial or complete data loss should an error or interruption happen. In this example, the contents of foo.txt are passed as input to a subshell (inside the parentheses) before the file is deleted. The previous inode stays alive as the subshell is keeping it open while reading data. The file written by the inner utility (here fold) while having the same name (foo.txt) points to a different inode because the old directory entry has been removed so technically, there are two different "files" with the same name during the process. When the subshell ends, the old inode is released and its data is lost. Beware to make sure you have enough space to temporarily store both the old file and the new one at the same time otherwise you'll lose data.

    (rm foo.txt; fold > foo.txt) < foo.txt 
`sponge` из [moreutils] (http://joeyh.name/code/moreutils/) также может помочь. `fold foo.txt | sponge foo.txt` - или `fold foo.txt | губка! $ `тоже надо делать. slhck 10 лет назад 3
@slhck Действительно, Губка тоже может справиться с этой задачей. Однако, поскольку ни POSIX, ни мейнстрим не указаны в Unix-подобных ОС, это вряд ли будет присутствовать. jlliagre 10 лет назад 0
Это не похоже на то, что его нельзя * сделать * подарком;) slhck 10 лет назад 0
7
Ignacio Vazquez-Abrams

The file is opened for writing by the shell before the application has a chance to read it. Opening the file for writing truncates it.

Похожие вопросы