Поддерживает ли sort сортировку файла на месте, например `sed --in-place`?

80

Я слепой или нет выбора, как --in-placeдля sort?

Чтобы сохранить результаты во входном файле, sed использует -i( --in-place).

Перенаправление вывода sortво входной файл

sort < f > f

приводит к тому, что он становится пустым. Если нет --in-placeвыбора - может быть, есть какая-то хитрость, как сделать это удобным способом?

(Единственное, что приходит мне в голову:

sort < f > /tmp/f$$ ; cat /tmp/f$$ > f ; rm /tmp/f$$

Перемещение не является правильным выбором, потому что права доступа к файлу могут быть изменены. Вот почему я перезаписываю содержимое временного файла, который затем удаляю.)

Гжегож Вежовецкий
источник
Существует также insituвозможность использования любых команд на месте.
sr_
@sr_, это интересная команда, но она не работает ни с какой командой, только с теми, которые пишут не быстрее, чем они читают (в противном случае это заглушит входной файл до того, как команда его прочитает). Там нет гарантии, что это будет работать с sort.
CJM
@ cjm, я действительно не уверен, но разве это не должно справиться с этим делом?
sr_
@ sr_, я думаю, что ты прав. Я читаю описание, а не смотрю на источник. Хотя для действительно больших файлов может не хватить памяти для буфера и сбоя (не похоже, что он проверяет NULL-возврат из malloc).
CJM
@cjm: О да, действительно.
sr_

Ответы:

110

sortимеет -o, --outputпараметр, который принимает имя файла в качестве аргумента. Если он совпадает с входным файлом, он записывает результат во временный файл, а затем перезаписывает исходный входной файл (точно так же, как и то, что sed -iделает).

Со GNU sortстраницы информации:

`-o OUTPUT-FILE'
`--output=OUTPUT-FILE'
      Write output to OUTPUT-FILE instead of standard output.  Normally,
      `sort' reads all input before opening OUTPUT-FILE, so you can
      safely sort a file in place by using commands like `sort -o F F'
      and `cat F | sort -o F'.  However, `sort' with `--merge' (`-m')
      can open the output file before reading all input, so a command
      like `cat F | sort -m -o F - G' is not safe as `sort' might start
      writing `F' before `cat' is done reading it.

      On newer systems, `-o' cannot appear after an input file if
      `POSIXLY_CORRECT' is set, e.g., `sort F -o F'.  Portable scripts
      should specify `-o OUTPUT-FILE' before any input files.

и из Открытой группы базовых спецификаций, выпуск 7 :

-o  output
    Specify the name of an output file to be used instead of the standard 
    output. This file can be the same as one of the input files.
enzotib
источник
Именно так ! Оно работает ! Я не вижу никакой подсказки об этом man sort- это недокументированная особенность? Это стандартно и портативно?
Гжегож Вежовецкий
@GrzegorzWierzowiecki: смотрите обновление.
энзотиб
Хороший ответ :).
Гжегож Вежовецкий
1
В заключение: sort -o <filename> <filename>безопасно отсортировать файл на месте.
Phyatt
11

Вы можете использовать spongeфункцию, которая сначала пропитывает, stdinа затем записывает ее в файл, например:

sort < f | sponge f

Недостатком spongeявляется то, что он будет хранить выходные данные временно в памяти, что может быть проблематично для больших файлов. В противном случае вы должны сначала записать его в файл, а затем перезаписать исходный файл.

Однако, как указывают другие ответы, изменения на месте, как правило, не очень хорошая идея, поскольку в середине процесса (например, spongeодного) машина может аварийно завершить работу, и тогда вы можете потерять как исходный, так и новый файл. Лучше сначала записать его в другой файл, а затем использовать атомарную mv(перемещение) инструкцию.

Виллем Ван Онсем
источник
7

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

Некоторые программы (в основном версии GNU) имеют опцию на месте (например, -iв perl и GNU sed; -oв сортировке GNU). Они работают, помещая данные во временный файл и затем перемещая его на место. Для программ , которые не имеют такой варианта, Колин Уотсон spongeутилита (входит в moreutils Джой Гесса ) делает работу безопасно для любой программы (примеры: Можем ли я сделать cut? Изменить файл на месте , как я могу сделать Iconv заменить входной файл с преобразованным выходной? )

Только в тех редких случаях, когда вы не можете восстановить исходный файл с теми же разрешениями, я рекомендую перезаписать файл на месте. В этом случае вам лучше сохранить исходный ввод где-нибудь. И тогда вы можете просто обработать копию ввода и отправить ее в исходный файл.

cp -p f ~/f.backup
sort <~/f.backup >|f
rm ~/f.backup # optional
жилль
источник
1
sort -oне специфичен для GNU и специально предназначен для переопределения файла на месте. sortне может начать запись своих выходных данных до того, как они полностью прочитают свои входные данные (использует память или временные файлы для хранения данных), поэтому вполне естественно, что он должен иметь возможность переопределить свои входные данные.
Стефан Шазелас
И на самом деле, это один из случаев, когда GNU sortне POSIX, так как sort -mo file1 file1 file2не гарантированно будет работать, в то время как традиционные sortS знают, как обойти это (уже в Unix V7 в 70-х).
Стефан Шазелас
@JoelCross Странно, sort -oу меня работает с coreutils 8.25, и это свойство задокументировано в руководстве (отмечая, что это только при сортировке, а не при объединении). Если вы можете воспроизвести это, отправьте отчет об ошибке (с указанием точной командной строки, точных входных файлов, в какой системе вы работаете и как вы получили двоичный файл).
Жиль
4

Используйте -oили попробуйте vim-way:

$ ex -s +'%!sort' -cxa file.txt
kenorb
источник