Почему не работает "sort file1> file1"? - PullRequest
16 голосов
/ 29 октября 2011

Когда я пытаюсь отсортировать файл и сохранить отсортированный вывод в себе, как это

sort file1 > file1;

, содержимое файла1 полностью стирается, тогда как когда я пытаюсь сделать то же самое сКоманда 'tee', подобная этой

sort file1 | tee file1;

, она отлично работает [ed: «отлично работает» только для небольших файлов с удачной синхронизацией, приведет к потере данных на больших или с бесполезным планированием процесса] , т.е. он перезаписывает отсортированный вывод файла file1 сам по себе, а также показывает его на стандартном выводе.

Может кто-нибудь объяснить, почему не работает первый случай?

Ответы [ 7 ]

18 голосов
/ 29 октября 2011

Как объяснили другие люди, проблема в том, что перенаправление ввода-вывода выполняется до выполнения команды sort, поэтому файл усекается до того, как sort получит возможность прочитать его. Если подумать немного, причина очевидна - оболочка обрабатывает перенаправление ввода / вывода и должна сделать это перед выполнением команды.

Команда sort имеет «всегда» (поскольку, по крайней мере, версия 7 UNIX) поддерживает опцию -o, чтобы было безопасно выводить в один из входных файлов:

sort -o file1 file1 file2 file3

Трюк с tee зависит от времени и удачи (и, вероятно, небольшого файла данных). Если у вас файл размером в мегабайт или больше, я ожидаю, что он будет перекрыт, по крайней мере частично, командой tee. То есть, если файл достаточно велик, команда tee откроет файл для вывода и урежет его до того, как sort закончит его чтение.

14 голосов
/ 29 октября 2011

Это не работает, потому что перенаправление '>' подразумевает усечение, и чтобы избежать сохранения всего вывода sort в памяти перед перенаправлением в файл, bash обрезает и перенаправляет вывод перед запуском sort. Таким образом, содержимое файла file1 будет усечено до того, как sort сможет прочитать его.

4 голосов
/ 29 октября 2011

Неразумно полагаться на то, что любая из этих команд будет работать так, как вы ожидаете.

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

sort file1 > file1.tmp && mv file1.tmp file1

Это позволяет избежать проблемы чтения файла после его частичной модификации, что может испортить результаты. Это также позволяет изящно справляться с ошибками; если длина файла составляет N байтов, а в файловой системе доступно только N / 2 байта пространства, вы можете обнаружить ошибку при создании временного файла и не выполнять переименование.

Или вы можете переименовать исходный файл, затем прочитать его и записать в новый файл с тем же именем:

mv file1 file1.bak && sort file1.bak > file1

Некоторые команды имеют опции для изменения файлов на месте (например, perl и sed обе имеют опции -i (обратите внимание, что синтаксис опции sed -i может отличаться). Но эти опции работают, создавая временные файлы, это просто сделано внутри.

1 голос
/ 26 марта 2016

Первая команда не работает (sort file1 > file1), потому что при использовании оператора перенаправления (> или >>) оболочка создает / усекает файл до того, как команда sort даже будет вызвана, поскольку она имеет более высокийприоритет.

Вторая команда работает (sort file1 | tee file1), потому что sort сначала читает строки из файла, а затем записывает отсортированные данные в стандартный вывод.

Таким образом, при использовании любой другой подобной команды, вы должны избегать использования оператора перенаправления при чтении и записи в один и тот же файл, но вы должны использовать соответствующие редакторы на месте (например, ex, ed, sed), например:

ex '+%!sort' -cwq file1

или используйте другие утилиты, такие как sponge.

К счастью, для sort есть параметр -o, который записывает результаты в файл (как предложено @ Jonathan ), поэтому решение является прямым: sort -o file1 file1.

1 голос
/ 29 октября 2011

Перенаправление имеет более высокий приоритет. Таким образом, в первом случае> file1 выполняется первым и очищает файл.

1 голос
/ 29 октября 2011

Bash открывает новый пустой файл, когда читает канал, а затем вызывает сортировку.

Во втором случае tee открывает файл после того, как сортировка уже прочитала содержимое.

0 голосов
/ 17 августа 2017

Вы можете использовать этот метод

sort file1 -o file1

Это позволит отсортировать и сохранить исходный файл. Также вы можете использовать эту команду для удаления дублирующейся строки:

sort -u file1 -o file1
...