Почему не выполняется сортировка файла file1> file1?
Когда я пытаюсь сортировать файл и сохранять отсортированный вывод сам по себе, например
sort file1 > file1;
содержимое файла1 полностью стирается, тогда как когда я пытаюсь сделать то же самое с командой "tee", как этот
sort file1 | tee file1;
он отлично работает [ed: "отлично работает" только для небольших файлов с удачным сроком, приведет к потерям данных на больших или с бесполезным планированием процессов], то есть перезаписывает отсортированный вывод file1, а также показывая его на стандартном выходе.
Может кто-нибудь объяснить, почему первый случай не работает?
Ответы
Ответ 1
Это не работает, потому что перенаправление " > " подразумевает усечение, и чтобы избежать сохранения всего вывода sort
в памяти перед повторным направлением к файлу, bash обрезает и перенаправляет вывод перед запуском sort
, Таким образом, содержимое файла file1
будет усечено до того, как sort
будет иметь возможность прочитать его.
Ответ 2
Как объяснили другие люди, проблема в том, что перенаправление ввода-вывода выполняется до того, как выполняется команда sort
, поэтому файл усечен до того, как sort
получит возможность прочитать его. Если вы немного поразмыслите, причина очевидна - оболочка обрабатывает перенаправление ввода-вывода и должна выполнить это перед запуском команды.
Команда sort
имеет "всегда" (поскольку, по крайней мере, версия 7 UNIX) поддерживает параметр -o
, чтобы сделать его безопасным для вывода на один из входных файлов:
sort -o file1 file1 file2 file3
Трюк с tee
зависит от времени и удачи (и, возможно, небольшого файла данных). Если у вас был мегабайт или более крупный файл, я ожидаю, что он будет скроен, по крайней мере частично, командой tee
. То есть, если файл достаточно велик, команда tee
откроет файл для вывода и усекает его до того, как sort
закончит чтение.
Ответ 3
Неразумно зависеть от любой из этих команд, чтобы работать так, как вы ожидаете.
Способ изменения файла на месте - это записать измененную версию в новый файл, а затем переименовать новый файл в исходное имя:
sort file1 > file1.tmp && mv file1.tmp file1
Это позволяет избежать проблемы с чтением файла после его частичного изменения, что, вероятно, испортит результаты. Это также позволяет грамотно справляться с ошибками; если файл имеет длину N байтов и в файловой системе имеется только N/2 байта пространства, вы можете обнаружить сбой создания временного файла и не выполнять переименование.
Или вы можете переименовать исходный файл, затем прочитать его и записать в новый файл с тем же именем:
mv file1 file1.bak && sort file1.bak > file1
Некоторые команды имеют опции для изменения файлов на месте (например, perl
и sed
оба имеют параметры -i
(обратите внимание, что синтаксис опции sed -i
может меняться). Но эти параметры работают путем создания временные файлы, это просто сделано внутренне.
Ответ 4
Bash открыть новый пустой файл при чтении канала, а затем вызывает сортировку.
Во втором случае tee открывает файл после сортировки, уже прочитавшего содержимое.
Ответ 5
Перенаправление имеет более высокий приоритет. Итак, в первом случае > file1 выполняет первый и опустошает файл.
Ответ 6
Первая команда не работает (sort file1 > file1
), потому что при использовании оператора перенаправления (>
или >>
) оболочка создает/обрезает файл до того, как команда sort
даже вызывается, так как она имеет более высокий старшинство.
Вторая команда работает (sort file1 | tee file1
), потому что sort
сначала считывает строки из файла, затем записывает отсортированные данные в стандартный вывод.
Поэтому при использовании любой другой подобной команды вам следует избегать использования оператора перенаправления при чтении и записи в один и тот же файл, но для этого вам следует использовать соответствующие редакторы на месте (например, ex
, ed
, sed
), например:
ex '+%!sort' -cwq file1
или использовать другие утилиты, такие как sponge
.
К счастью для sort
существует параметр -o
, который записывает результаты в файл (как это предложено @Jonathan), поэтому решение прямолинейно: sort -o file1 file1
.
Ответ 7
Вы можете использовать этот метод
sort file1 -o file1
Это приведет к сортировке и сохранению исходного файла. Кроме того, вы можете использовать эту команду для удаления дублированной строки:
sort -u file1 -o file1