Unikalne sortowanie: Przekieruj wyjście do tego samego pliku

14

Czy istnieje jakiś krótki sposób na zapisanie wyniku potoku w tym samym pliku, który jest przetwarzany. Na przykład to właśnie robię

$ cat filename | sort | uniq > result
$ rm -f filename
$ mv result filename

Zastanawiałem się, czy można to zrobić w jednym wierszu (nie dodając tych poleceń za pomocą &&)

To nie jest droga, ale znalezienie pomysłu

$ cat filename | sort | uniq > filename
whitenoisedb
źródło
2
echo $(cat filename | sort | uniq > result) > filenamelub coś ? Przechodząc, nie mam czasu, aby tego spróbować.
MrVaykadji

Odpowiedzi:

18

Możesz użyć spongez pakietu moreutils :

LC_ALL=C sort -u filename | sponge filename

Nie potrzebujesz też potoku do uniq, ponieważ kiedy sortma -uopcję unikatowych linii podczas sortowania.

Zauważ, że w systemie GNU z ustawieniami narodowymi UTF-8, sort -ulub sort | uniqnie dawał ci unikalnych linii, ale pierwszy z sekwencji linii, które sortują to samo w bieżącym locale.

$ printf '%b\n' '\U2460' '\U2461' | LC_ALL=en_US.utf8 sort | LC_ALL=en_US.utf8 uniq

dałem ci tylko . Zmiana ustawień regionalnych na C wymusza porządek sortowania na podstawie wartości bajtów:

$ export LC_ALL=C
$ printf '%b\n' '\U2460' '\U2461' | LC_ALL=C sort | LC_ALL=C uniq

Cuonglm
źródło
12

Nie potrzebujesz żadnych dodatkowych poleceń, takich jak cati uniqbez użycia rmpolecenia i mvpolecenia do usunięcia i zmiany nazwy pliku. wystarczy użyć prostej komendy.

sort -u filename -o filename


 -u, --unique
        with -c, check for strict ordering; without -c, output only  the
        first of an equal run

 -o, --output=FILE
        write result to FILE instead of standard output

Jak to działa?

sortpolecenie sortuje nazwę pliku iz -uopcją usuwa z niego zduplikowane linie. następnie z -oopcją zapisuje dane wyjściowe do tego samego pliku metodą lokalną.

αғsнιη
źródło
3
W przypadku awarii systemu podczas sortdziałania utracisz oryginalny plik.
cuonglm
@Gnouc Więc to koniec pecha !! : „(
αғsнιη
1
dzięki! w tym przykładzie, szczególnie „sort”, powinienem to zrobić. Myślałem jednak o ogólnym przypadku. @Gouou, haha, nie ma sposobu, aby pomyśleć, że gdyby ci się to nie przydarzyło, prawda?
whitenoisedb
3

Sugerowany przez Ciebie przykład (poniżej) nie działa, ponieważ faktycznie będziesz jednocześnie czytać i zapisywać do tego samego pliku.

$ cat filename | sort | uniq > filename

Idea z potokiem lub przekierowaniem polega na tym, że polecenie po lewej i prawej stronie każdej potoku lub przekierowania działa równolegle. Polecenie po prawej przetwarza informacje, które są mu przekazywane z polecenia po lewej stronie, podczas gdy polecenie po lewej stronie jest nadal uruchomione.

Aby scenariusz zadziałał, polecenie, które odczytuje z pliku, musiałoby zakończyć się przed uruchomieniem polecenia zapisującego do pliku. Aby to zadziałało, musisz najpierw przekierować dane wyjściowe do lokalizacji tymczasowej, a następnie, gdy to się skończy, wyślij je z lokalizacji tymczasowej z powrotem do pliku.

Lepszym sposobem na to jest w zasadzie jak w poprzednim przykładzie, w którym przekierowujesz do pliku tymczasowego, a następnie zmieniasz nazwę tego pliku z powrotem na oryginalny (z wyjątkiem tego, że nie musisz najpierw usuwać pliku, ponieważ przeniesienie usuwa dowolny istniejący cel) .

$ cat filename | sort | uniq > result
$ mv -f result filename

Możesz także zapisać go w zmiennej łańcuchowej, z tą różnicą, że działa tylko wtedy, gdy dane są wystarczająco małe, aby zmieścić się w pamięci jednocześnie.

thomasrutter
źródło
Ponieważ ktoś zgłasza sugerowaną edycję, możesz zmienić cat filename | sortna just sort filename- cattutaj nie jest to konieczne.
thomasrutter
Mój przykład poniżej nie był tym sposobem. Dzięki za wyjaśnienie. catw tym przypadku może być niepotrzebne, ale skupiłem się na części przekierowującej.
whitenoisedb
1
Wyjaśniłem, dlaczego twój poniższy przykład nie zadziała. Wiem, że wiedziałeś, że to nie działa.
thomasrutter
Dzięki za wytłumaczenie! W rzeczywistości nie wiedziałem, co się naprawdę dzieje.
whitenoisedb
2

Możesz użyć teepolecenia:

sort -u filename | tee filename > /dev/null

teeKomenda czyta ze standardowego wejścia i zapisuje na standardowe wyjście i plików.

Sylvain Pineau
źródło
2
To mi nie działa.
pjvandehaar
3
To nie działa askubuntu.com/a/752451
Steven Penny
To nie praca dla mnie. np. aby przenieść linię na dół pliku: (cat ~/file | grep -v 3662 ; printentry 3662) | tee ~/file > /dev/nulldziała. Podobnie jak oryginalny post, to nie działa, jeśli tylko > ~/filebez tee. Tee wydaje się tutaj podobny do sort -o file, który zapisuje do nazwanego pliku bez kontynuowania tej samej potoku.
Joshua Goldberg,
Czekaj, przepraszam! Widziałem empirycznie, że to nieprzewidywalnie utraci dane, jak wyjaśniono w linku z @Steven. Utwórz plik o numerach 1..9 w 9 liniach. Następujące działania będą działać kilka razy, a następnie od czasu do czasu usuwają wszystkie dane z pliku: (cat x | grep -v 7 ; echo 7) | tee x > /dev/null; cat x Polecam plik tymczasowy i / mvlub rozwiązanie z linku @ Steven.
Joshua Goldberg,
@JoshuaGoldberg, czy widziałeś moją odpowiedź na tej stronie?
Steven Penny,
0

Możesz używać Vima w trybie Ex:

ex -sc 'sort u|x' filename
  1. sort u sortuj unikalne

  2. x napisz, jeśli zmiany zostały wprowadzone (mają) i wyjdź

Steven Penny
źródło