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


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.

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ś).


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

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.