Właśnie uruchomiłem następujące polecenie bash:
uniq .bash_history > .bash_history
a mój plik historii skończył się zupełnie pusty.
Chyba potrzebuję sposobu na odczytanie całego pliku przed jego zapisaniem. Jak to się robi?
PS: Oczywiście myślałem o użyciu pliku tymczasowego, ale szukam bardziej eleganckiego rozwiązania.
bash
nie umieści kolejnych duplikatów w swojej historii, jeśli ustawisz HISTCONTROL, aby zawierał ignorowane kopie; zobacz stronę podręcznika.Odpowiedzi:
Polecam używanie
sponge
z moreutils . Z strony podręcznika:Aby zastosować to do swojego problemu, spróbuj:
źródło
Chciałem tylko przekazać kolejną odpowiedź, która jest prosta i nie używa gąbki (ponieważ często nie jest zawarta w lekkich środowiskach).
powinien mieć pożądany rezultat. Ta podpowłoka jest wykonywana, zanim plik .bash_history zostanie otwarty do zapisu. Jak wyjaśniono w odpowiedzi Phila P., do czasu odczytania .bash_history w oryginalnym poleceniu zostało już obcięte przez operatora „>”.
źródło
$()
zamiast backticków z powodu pewnych problemów związanych z ucieczką.echo "$(fmt -p '# ' -w 50 readme.txt)" > readme.txt
dzisiaj. Długo szukałem eleganckiego rozwiązania. Wielkie dzięki, @Hart Simha!Problem polega na tym, że powłoka konfiguruje potok poleceń przed uruchomieniem poleceń. Nie chodzi o „dane wejściowe i wyjściowe”, lecz o to, że zawartość pliku zniknęła, zanim uniq się uruchomi. To idzie mniej więcej tak:
>
plik wyjściowy do zapisu, obcinając goIstnieją różne rozwiązania, w tym edycja na miejscu i tymczasowe użycie pliku, o których wspominają inni, ale kluczem jest zrozumienie problemu, co właściwie nie działa i dlaczego.
źródło
Kolejną sztuczką, aby to zrobić bez użycia
sponge
, jest następujące polecenie:Jest to jeden z kodów opisanych w doskonałym artykule „Edycja na miejscu” plików na backreference.org.
Zasadniczo otwiera plik do odczytu, a następnie „usuwa” go. Jednak tak naprawdę nie został usunięty: wskazuje na niego otwarty deskryptor pliku i dopóki jest on otwarty, plik jest nadal dostępny. Następnie tworzy nowy plik o tej samej nazwie i zapisuje w nim unikalne linie.
Wada tego rozwiązania: jeśli
uniq
z jakiegoś powodu zawiedzie, Twoja historia zniknie.źródło
użyj gąbki z moreutils
źródło
Ten
sed
skrypt usuwa sąsiadujące duplikaty. Z tą-i
opcją dokonuje modyfikacji na miejscu. Pochodzi zsed
info
pliku:źródło
strace
ilustracją (nie żeby to naprawdę miało znaczenie) :-)process input > tmp && mv tmp input
jest o wiele prostsze i bardziej czytelne niż stosowaniesed
sztuczek po prostu w celu uniknięcia pliku tymczasowego i nie zastąpi mojego oryginału, jeśli się nie powiedzie (nie wiem, czysed -i
zawodzi z wdziękiem - zrobiłbym to myślę, że tak). Poza tym istnieje wiele rzeczy, które można zrobić za pomocą metody pliku wyjściowego do pliku tymczasowego, których nie można zrobić w miejscu bez czegoś bardziej zaangażowanego niż tensed
skrypt. Wiem, że wiesz o tym wszystkim, ale może to przynieść korzyści niektórym gapiom.Jako ciekawą ciekawostkę sed używa również pliku tymczasowego (robi to za Ciebie):
Opis:
plik tymczasowy zmienia
./sedPmPv9z
się na fd 4, afoo
pliki na fd 3. Operacje odczytu są wykonywane na fd 3, a zapis na fd 4 (plik tymczasowy). Plik foo jest następnie nadpisywany plikiem temp w wywołaniu zmiany nazwy.źródło
Inne rozwiązanie:
źródło
Plik tymczasowy to w zasadzie, chyba że dane polecenie obsługuje edycję w miejscu (
uniq
nie - niektóresed
s do (sed -i
)).źródło
Możesz używać Vima w trybie Ex:
%
wybierz wszystkie linie!
Uruchom poleceniex
Zapisz i zamknijźródło
Możesz również użyć tee, używając danych wyjściowych uniq jako danych wejściowych:
źródło