Staram się przechowywać ostatnie 50 wierszy w moim pliku, w którym oszczędzam temperaturę co minutę. Użyłem tego polecenia:
tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test
Ale wynikiem jest pusty plik testowy. Myślałem, że wyświetli ostatnie 50 wierszy pliku testowego i wstawi go do pliku testowego. Kiedy używam tego polecenia:
tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test2
działa dobrze. Plik test2 zawiera 50 wierszy.
Czy ktoś może mi wyjaśnić, gdzie jest problem?
command-line
logs
tail
dorinand
źródło
źródło
logging
modułuOdpowiedzi:
Problem polega na tym, że powłoka konfiguruje potok poleceń przed uruchomieniem poleceń. Nie chodzi o „wejście i wyjście”, ale o to, że zawartość pliku zniknęła, zanim jeszcze uruchomi się tail. To idzie mniej więcej tak:
>
plik wyjściowy do zapisu, obcinając gotail
.tail
uruchamia się, otwiera/home/pi/Documents/test
i niczego tam nie znajdujeIstnieją różne rozwiązania, ale kluczem jest zrozumienie problemu, co właściwie idzie nie tak i dlaczego.
To da ci to, czego szukasz,
Objaśnienie:
$()
nazywa się zastępowaniem poleceń, które wykonujetail -n 50 /home/pi/Documents/test
> /home/pi/Documents/test
przekierowuje wyjścieecho "$(tail -n 50 /home/pi/Documents/test)"
do tego samego pliku.źródło
bash: xrealloc: cannot allocate 18446744071562067968 bytes
Innym rozwiązaniem przekierowania pliku najpierw wyczyszczającego plik jest użycie
sponge
zmoreutils
pakietu w następujący sposób:źródło
Wynika to z tego, że bash przetwarza przekierowanie z
>
pierwszym, usuwając zawartość pliku. Następnie wykonuje polecenie. Gdybyś używał>>
, ostatnie 50 wierszy zostanie dołączonych na końcu tego, co aktualnie znajduje się w pliku. W takim przypadku powtórzyłbyś dwa razy te same 50 wierszy.Polecenie działa zgodnie z oczekiwaniami podczas przekierowywania do innego pliku. Oto jeden ze sposobów zapisania ostatnich 50 wierszy pliku do pliku o tej samej nazwie:
Najpierw zapisuje ostatnie 50 wierszy do pliku tymczasowego, który jest następnie przenoszony przy użyciu
mv
zastępowania oryginalnego pliku.Jak zauważono w komentarzach, to nie zadziała, jeśli plik jest nadal otwarty. Przeniesienie pliku powoduje także utworzenie nowego i-węzła i może zmienić własność i uprawnienia. Lepszym sposobem na to przy użyciu pliku tymczasowego byłoby:
Plik tymczasowy można również usunąć, ale za każdym razem jego zawartość zostanie zastąpiona.
źródło
tail -50 /home/pi/Documents/test >/tmp/foo && cat /tmp/foo >/home/pi/Documents/test
tail ... > temp ; cat temp > orig ; rm -f temp
Prace.Ponieważ widziałeś główny problem z przekierowaniem powłoki, oto alternatywny sposób przycinania pliku do jego ostatnich 50 wierszy:
Ciężką pracę wykonuje (GNU) sed z
-i
funkcją „edycji na miejscu”, która działa pod przykryciem, tworząc wyjście w pliku tymczasowym. Reszta linii konfiguruje matematykę dla operacji sed, a mianowicie:wc
), a następnie odejmij 50; przypisz to don
.n
jest dodatnia, uruchom polecenie sed, aby usunąć linie od 1 do n.źródło
printf
służy do wprowadzania poleceń (po jednym w wierszu) doed
. Teed
polecenia są:1,$-50d
- usuń wszystkie oprócz ostatnich 50 wierszyw
- zapisz zmodyfikowany plik z powrotem na dyskNie ma żadnych przekierowań, więc powłoka nie może nadpisać pliku wyjściowego przed jego odczytaniem.
Ponadto, w przeciwieństwie do większości form edycji „na miejscu” (które zwykle symulują edycję „na miejscu”, tworząc plik tymczasowy, a następnie zmieniając jego nazwę na oryginał),
ed
tak naprawdę edytuje plik oryginalny - więc zachowuje ten sam i-węzeł ( oraz właściciel, grupa i uprawnienia - plik tymczasowy + mv zawsze zmieni i-węzeł i może zmienić inne w zależności od okoliczności).źródło
Na nieco innej ścieżce możesz
logrotate(8)
regularnie tworzyć kopie zapasowe plików dziennika w plikach o nazwach przyrostowych, a następnie usuwać stare.W ten sposób zarządza się głównymi plikami dziennika systemowego, aby nie rosły zbyt długo.
źródło