Czy sort obsługuje sortowanie pliku w miejscu, na przykład `sed --in-place`?

80

Czy jestem ślepy czy nie ma takiej opcji jak --in-placedla sort?

Aby zapisać wyniki w pliku wejściowym, sed używa -i( --in-place).

Przekierowanie wyjścia sortdo pliku wejściowego

sort < f > f

powoduje, że jest pusty. Jeśli nie ma --in-placeopcji - może jest jakaś sztuczka, jak to zrobić w poręczny sposób?

(Jedyne, co przychodzi mi do głowy:

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

Przenoszenie nie jest właściwym wyborem, ponieważ uprawnienia do plików mogą ulec zmianie. Dlatego nadpisuję zawartość pliku tymczasowego, który następnie usuwam.)

Grzegorz Wierzowiecki
źródło
Istnieje również insitumożliwość używania dowolnych poleceń w miejscu.
sr_
@ sr_, to ciekawe polecenie, ale nie działa z żadnym poleceniem, tylko z tymi, które piszą nie szybciej niż czytają (w przeciwnym razie plik wejściowy zostanie zablokowany, zanim polecenie to przeczyta). Nie ma gwarancji, że będzie działać sort.
cjm
@cjm, ja naprawdę nie jestem pewien, ale nie jest to powinien obsługiwać tę sprawę?
sr_
@ sr_, myślę, że masz rację. Czytam opis zamiast patrzeć na źródło. Chociaż w przypadku naprawdę dużych plików może zabraknąć pamięci dla bufora i zawiesić się (nie wygląda na to, że sprawdza NULL powrotu z malloc).
cjm
@cjm: O tak, rzeczywiście.
sr_

Odpowiedzi:

110

sortma -o, --outputopcję, która przyjmuje nazwę pliku jako argument. Jeśli jest taki sam jak plik wejściowy, zapisuje wynik do pliku tymczasowego, a następnie zastępuje oryginalny plik wejściowy (dokładnie to samo, co sed -irobi).

Ze GNU sortstrony informacyjnej:

`-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.

oraz ze specyfikacji bazowej Open Group Problem 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
źródło
Dokładnie ! To działa ! Nie widzę w tym żadnych wskazówek man sort- czy jest to funkcja nieudokumentowana? Czy to jest standardowe i przenośne?
Grzegorz Wierzowiecki
@GrzegorzWierzowiecki: patrz aktualizacja.
enzotib
Niezła odpowiedź :).
Grzegorz Wierzowiecki
1
Podsumowując: sort -o <filename> <filename>bezpiecznie posortuje plik na miejscu.
phyatt
11

Możesz użyć spongefunkcji, która najpierw nasiąka, stdina następnie zapisuje ją do pliku, na przykład:

sort < f | sponge f

Minusem spongejest to, że będzie przechowywać dane tymczasowe w pamięci, co może być problematyczne w przypadku dużych plików. W przeciwnym razie musisz najpierw zapisać plik, a następnie nadpisać oryginalny plik.

Jak jednak wskazują inne odpowiedzi, modyfikacje w miejscu nie są ogólnie dobrym pomysłem, ponieważ w trakcie procesu (na przykład tego sponge) maszyna może ulec awarii, a następnie można utracić zarówno oryginalny, jak i nowy plik. Lepiej najpierw napisz go do innego pliku, a następnie użyj instrukcji atomowej mv(przenieś).

Willem Van Onsem
źródło
7

Zastąpienie pliku wejściowego plikiem wyjściowym jest niebezpieczne, ponieważ jeśli program lub system ulegnie awarii podczas zapisywania pliku, utracisz oba.

Kilka programów (głównie wersje GNU) ma opcję na miejscu (np. -iNa perlu i GNU sed; -ona sortowaniu GNU). Działają, umieszczając dane w pliku tymczasowym, a następnie przenosząc je na miejsce. Dla programów, które nie mają takiej możliwości, Colin Watson spongenarzędzie (wliczone w moreutils Joey Hessa ) spełnia swoje zadanie bezpiecznie dla każdego programu (przykłady: mogę zrobić cut? Zmienić plik na swoim miejscu ; Jak mogę dokonać iconv zastąpić plik wejściowy z konwersją wyjście? ).

Tylko w tych rzadkich przypadkach, w których nie można odtworzyć oryginalnego pliku z tymi samymi uprawnieniami, zalecam zastąpienie tego pliku. W takim przypadku lepiej gdzieś zapisać oryginalne dane wejściowe. Następnie możesz po prostu przetworzyć kopię danych wejściowych i wysłać ją do oryginalnego pliku.

cp -p f ~/f.backup
sort <~/f.backup >|f
rm ~/f.backup # optional
Gilles
źródło
1
sort -onie jest specyficzny dla GNU i jest specjalnie zaprojektowany do lub przywracania pliku w miejscu. sortnie może zacząć zapisywać danych wyjściowych, zanim w pełni nie odczyta danych wejściowych (używa pamięci lub plików tymczasowych do przechowywania danych), więc jest całkiem naturalne, że powinno być w stanie zastąpić dane wejściowe.
Stéphane Chazelas
I faktycznie, jest to jeden przypadek, w którym GNU sortnie jest POSIX-em, ponieważ sort -mo file1 file1 file2nie ma gwarancji, że zadziała, podczas gdy tradycyjni sortwiedzą, jak to obejść (już w Unixie V7 w latach 70.).
Stéphane Chazelas
@JoelCross Odd, sort -odziała dla mnie z coreutils 8.25, a właściwość jest udokumentowana w instrukcji (zauważając, że ma to miejsce tylko podczas sortowania, a nie podczas scalania). Jeśli możesz to odtworzyć, wyślij raport o błędzie (wskazujący dokładny wiersz poleceń, dokładny plik (pliki) wejściowe, system, na którym go uruchomiłeś i sposób uzyskania pliku binarnego).
Gilles
4

Użyj -olub wypróbuj vim-way:

$ ex -s +'%!sort' -cxa file.txt
kenorb
źródło