Dlaczego miałbyś `cat / dev / null> / var / log / messages`?

77

Na tej przykładowej stronie skryptu bash autor przedstawia ten skrypt:

# Cleanup
# Run as root, of course.

cd /var/log
cat /dev/null > messages
cat /dev/null > wtmp
echo "Log files cleaned up."

Dlaczego miałbyś się cat /dev/nullna co wybierać? Nie mogę zrozumieć, co ma tutaj (to jest jak za pomocą while TRUE; sleep 1; elihwdla {some busy program}?). Jednak autor nazywa to „niczym niezwykłym”.

izomorfizmy
źródło

Odpowiedzi:

41

Zazwyczaj, cat /dev/null > [something]gdy chcesz wyczyścić zawartość pliku, zapewniając absolutnie zerowe ryzyko zakłócenia rzeczywistego stanu pliku. Zawartość pliku zostanie wyczyszczona przez cat /dev/nullsam plik - ponieważ istnieje i jest znany systemowi plików, w którym rezyduje - nadal będzie miał ten sam numer i-węzła, własność i uprawnienia.

W przypadku pliku dziennika może być tak, że sam plik dziennika jest oznaczony jako „w użyciu” przez inny proces. Takie postępowanie, na przykład, rm /var/log/messages && touch /var/log/messagesmoże zakłócać inne procesy i może powodować dławienie uruchomionych procesów. Oznacza to, że proces, który w jakiś sposób jest powiązany z określonym numerem i-węzła podłączonym do pliku, /var/log/messagesmoże nagle wpaść w panikę i powiedzieć: „Hej! Co się stało /var/log/messages! ”, Nawet jeśli plik nadal tam jest. Nie wspominając już o potencjalnych problemach z nieprawidłowym odtwarzaniem własności i uprawnień.

Z powodu tej niepewności w użyciu / stanie pliku, korzystanie z niego cat /dev/null > [something]jest preferowane przez administratorów systemu, którzy chcą wyczyścić dziennik, ale nie chcą potencjalnie zakłócać działania już istniejących procesów.

Ponadto w kontekście strony, do której prowadzi link do autora, stwierdza:

Nie ma tu nic niezwykłego, tylko zestaw poleceń, które równie łatwo można było wywoływać jeden po drugim z wiersza poleceń na konsoli lub w oknie terminala. Zalety umieszczania poleceń w skrypcie wykraczają daleko poza to, że nie trzeba ich wielokrotnie wpisywać.

Zatem „nic niezwykłego”, o którym wspomina autor, dotyczy całej koncepcji tego konkretnego skryptu bash: jest to tylko zestaw prostych poleceń, które można równie łatwo uruchomić z wiersza poleceń, ale umieszcza się w pliku tekstowym, aby unikaj powtarzania ich w kółko.

JakeGould
źródło
10
@jlliagre Jedyną rzeczą, którą „utrzymuje się przy życiu”, jest kontekst pytania, które koncentruje się na tym, dlaczego oryginalny autor to zrobił. Jeśli masz zamiar obalić „mit”, opublikuj odpowiedź, która zawiera kontekst dla metody kodowania oryginalnego autora, a także perspektywę, dlaczego Twoim zdaniem można ją zastąpić innymi metodami.
JakeGould,
7
Odpowiedź @jlliagre Cyrus nie odnosi się do podstawowego pytania, dlaczego pierwotny autor zastosowałby tę metodę, ani uzasadnienia. Wspomniany samouczek jest dość stary i dość dobrze przyjęty. To nie jest niepoprawne ani nie utrwala rzekomej „miejskiej legendy”. Raczej jest to sposób, w jaki jedna osoba koduje, a sposób, w jaki inna osoba koduje. Tak proste jak to. Jest to problem związany ze stylem, który nie ma negatywnego wpływu na niezawodność ani wydajność.
JakeGould,
3
truncate -s 0zrobiłby to samo i byłby mniej idiomatyczny. Jednak programiści powłoki są konserwatywną grupą i można napotkać systemy wystarczająco stare lub wystarczająco zwariowane, aby nie mieć tego polecenia.
Schwern,
5
@skift cat /dev/null > /foo/barobcina plik; echo "" > /foo/barobcina go, a następnie zapisuje pojedynczy znak nowej linii.
David
2
Kolejną zaletą tej metody w porównaniu z rm & touch jest utrzymanie własności i uprawnień.
jjmontes,
121

Dlaczego miałbyś cat / dev / null na czymkolwiek?

Zrobisz to, aby obciąć zawartość pliku, zachowując nienaruszony i-węzeł. Wszystkie programy, które mają ten plik otwarty do odczytu lub zapisu, nie miałyby wpływu poza tym, że rozmiar pliku zostałby zresetowany do zera.

Fałszywą często znajdowaną alternatywą jest usunięcie pliku, a następnie utworzenie go ponownie:

rm file
touch file

lub podobny:

mv file file.old
gzip file.old
touch file

Problem polega na tym, że te metody nie zapobiegają zapisywaniu starego pliku przez jakiekolwiek procesy, w których usunięty plik jest otwarty podczas usuwania. Powodem jest to, że w systemach plików Unix, kiedy usuwasz plik, odłączasz tylko jego nazwę (ścieżkę) od jego zawartości (i-węzła). I-węzeł jest utrzymywany przy życiu tak długo, jak istnieją procesy, które otwierają go do czytania lub pisania.

Prowadzi to do kilku negatywnych skutków: dzienniki zapisane po usunięciu pliku są tracone, ponieważ nie ma prostego / przenośnego sposobu otwarcia usuniętego pliku. Tak długo, jak proces zapisuje do usuniętego pliku, jego zawartość nadal zajmuje miejsce w systemie plików. Oznacza to, że jeśli usuniesz / utworzysz plik, ponieważ wypełniał on dysk, dysk pozostanie wypełniony. Jednym ze sposobów rozwiązania tego ostatniego problemu jest ponowne uruchomienie procesów rejestratora, ale możesz tego nie chcieć w przypadku krytycznych usług, a dzienniki pośredniczące zostaną ostatecznie utracone. Istnieją również skutki uboczne, ponieważ tworzony plik może nie mieć takich samych uprawnień, właściciela i grupy jak oryginalny. Może to na przykład uniemożliwić analizatorowi dziennika odczytanie nowo utworzonego pliku lub, co gorsza, uniemożliwić procesowi zapisywania własnych dzienników.

Pierwsza metoda, cat /dev/null > fileosiągnij cel właściwie, jednak pomimo wytrwałej miejskiej legendy, jej cat /dev/nullczęść nie robi absolutnie nic pożytecznego. Otwiera pseudoplik, który z założenia jest pusty, niczego nie czyta, a na koniec wychodzi. Użycie tego polecenia jest wówczas marnotrawstwem naciśnięć klawiszy, bajtów, wywołań systemowych i cykli procesora, i można je zastąpić bez żadnych zmian funkcjonalnych niewątpliwie szybszym poleceniem no-op, :a nawet, w przypadku większości powłok, żadnym poleceniem.

Pozwól mi spróbować metafory, aby wyjaśnić, jak bezużyteczne cat /dev/nulljest. Powiedzmy, że Twoim celem jest opróżnienie szklanki.

  • Najpierw usuwasz z niego płyn. Jest to wystarczające i właśnie to ( > file) robi, biorąc pod uwagę fakt, że przekierowania są zawsze przetwarzane jako pierwsze.

  • Następnie wybierz pustą butelkę ( /dev/null) i wlej ją do pustej szklanki ( cat). To bezcelowy krok ...

Jeśli czytasz połączony dokument do końca, możesz zauważyć komentarze w tym wierszu z ulepszonej wersji skryptu:

    cat / dev / null> wtmp #   ':> wtmp' i '> wtmp' mają ten sam efekt.

Oni rzeczywiście; szkoda cat /dev/nullbyła trzymana w kodzie.

To oznacza, że następujący kod będzie działać we wszystkich wspólnych muszli (zarówno cshi shrodziny):

cd /var/log
: > messages
: > wtmp
echo "Log files cleaned up."

i to będzie działać ze wszystkimi muszli przy użyciu składni Bourne, jak ash, bash, ksh, zshi lubi:

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."

Zauważ jednak, że w starożytnych powłokach Bourne'a sprzed POSIX-a dowolne z tych poleceń, w tym cat /dev/nullnie obcinają pliku, jeśli zostanie on później napisany przez wciąż działający skrypt powłoki dołączający się do niego. Zamiast pliku z bajtami zerowymi byłby to plik rzadki z niezmienionym rozmiarem. To samo stałoby się, gdyby plik został napisany przez proces dążący do pozycji, którą uważa za aktualną przed zapisaniem.

Uwaga: niektóre alternatywne rozwiązania często sugerowane do obcięcia pliku mają wady.

  • Oba poniższe po prostu nie wykonują zadania. Wynikowy plik nie jest pusty, ale zawiera pustą linię. Spowodowałoby to uszkodzenie plików dziennika takich jak te, wtmpktóre przechowują rekordy o stałej szerokości.

    echo > file
    echo "" > file
  • Kolejny oparty na shopcji BSD nie jest przenośny, POSIX nie określa żadnych dozwolonych opcji echa, więc możesz skończyć z plikiem zawierającym wiersz z „ -n”:

    echo -n > file
  • Ten też nie jest przenośny przy użyciu shsekwencji ucieczki Systemu V. Niektóre powłoki utworzą plik zawierający wiersz z „ \c”:

    echo "\c" > file
  • Ten używa polecenia zaprojektowanego do wykonania zadania. Problem polega na truncatetym, że nie można go przenosić, ponieważ w systemie Unix / Linux może brakować tego polecenia, które nie zostało określone przez POSIX.

    truncate -s 0

Wreszcie, oto kilka alternatyw, które są przenośne i właściwie wykonają zadanie:

  • Jawne drukowanie pustego ciągu do pliku:

    printf "" > file
  • Za pomocą truepolecenia, które jest ściśle równoważne poleceniu no-op, :choć bardziej czytelne:

    true > file
jlliagre
źródło
1
@JathanathanLeffler Wierzę, że jest to część wszystkich obecnych cshwdrożeń, chociaż niekoniecznie jest to udokumentowane. Ze strony csh podręcznika Solaris : Null command. This command is interpreted, but performs no action.. Nie znalazłem żadnej wzmianki o tym samym ani na tcshstronie podręcznika, ani na stronie BSD csh, ale ta składnia mogła zawsze działać.
jlliagre
6
Jednym z powodów, dla których piszesz, cat /dev/nulljest wyraźne zamierzenie.
Davidmh,
1
@Davidmh To byłoby rozsądne, ale twoje oświadczenie nie opiera się sprawdzaniu faktów. Ten idiom powłoki obserwowałem prawdopodobnie przez kilka dekad. Kiedy miałem okazję zapytać autora o uzasadnienie, zawsze miałem niezrozumiałe teorie na temat używania /dev/nullskutecznego sposobu wprowadzania zerowych bajtów, zresztą bardziej niezawodnego niż używanie :lub nic. W tym samym stronie Cyrus odpowiedź co było lakoniczne, ale prosto do punktu, miał zero głosów, podczas gdy jeden JakeGould za który kwestionuje fakt cat /dev/nullbył no-op (zobacz nasze komentarze) już co najmniej cztery głosy.
jlliagre
2
@ jlliagre moja wiedza na temat powłoki jest dość podstawowa, więc być może nie jestem najlepszym celem populacji; ale goły >lub :nie jest jasne. Zgadzam się, że szkoda, że ​​mity zostały rozpowszechnione z powodu ich użycia.
Davidmh,
4
@Davidmh Jeśli naprawdę chcesz czegoś wyraźnego przed przekierowaniem, polecam, printf "" > filektóry jest zarówno przenośny (POSIX), jak i lekki tak często, jak wbudowany w powłokę.
jlliagre
6

Jest to nieporęczny sposób na doprowadzenie pliku do zera.

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."
Cyrus
źródło
Ta składnia nie działa w każdej powłoce.
reinierpost
2
Poprawny. Pytanie jest oznaczone tylko „bash”.
Cyrus
@reinierpost Będzie działać we wszystkich powłokach w stylu Bourne'a, prawda? Nie martwmy się o to csh.
Barmar,
: > messagesdziała również. :lub truesą bardziej oczywistymi wyborami dla poleceń, które nie wypisują niczego i zwracają wartość true.
Peter Cordes
-3

Aby obciąć otwarty plik. Jest to równoważne i bardziej zrozumiałe:

echo -n > /var/log/messages

(Dodano -n, aby uniknąć nowej linii)

bbaassssiiee
źródło
3
Jest to rzeczywiście bardziej zrozumiałe, ale niestety nie równoważne. Zniszczy nawet funkcjonalność, jak w wtmpprzypadku. Zobacz moją zaktualizowaną odpowiedź.
jlliagre
echo -n unika nowej linii.
bbaassssiiee
6
To rzeczywiście będzie, jeśli jesteś pewien, że użyjesz bash, w -nprzeciwnym razie nie będzie działać we wszystkich powłokach Bourne'a.
jlliagre