cat / dev / null> file.log nie obcina dużego pliku w Darwin

15

W przeszłości, w systemach Linux, byłem w stanie obcinać duże, otwarte pliki dziennika (to znaczy plik, który jest aktywnie zapisywany przez proces) przy użyciu cat /dev/null > file.log.

Jednak w wersji 10.9 (Mavericks) tak nie jest. Mam plik 11 GB, do którego loguje się aplikacja, ale kiedy wykonuję to samo polecenie z tym plikiem, wydaje się, że nic się nie dzieje.

Kiedy próbuję tego na trywialnym pliku, to działa.

Oto ls -l /dev/null:

crw-rw-rw- 1 root wheel 3, 2 Dec 16 12:49 /dev/null

Próbowałem też cp /dev/null file.logbezskutecznie.

Myśląc, że mógłbym skorzystać z funkcji obcinania ( man 2 truncatew Darwin), skompilowałem to i uruchomiłem na dwóch plikach, jednym o trywialnym rozmiarze, a drugim na prawdziwym pliku dziennika. Ponownie działało to przeciwko trywialnemu plikowi i nie działało na znacznie większym dzienniku.

/*
 * Copyright (c) 2013 Thomas de Grivel <[email protected]>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 ...
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <unistd.h>

int main (int argc, const char **argv)
{
        int e = 0;
        while (--argc) {
                argv++;
                if (truncate(*argv, 0)) {
                        e = 4;
                        warn("%s", *argv);
                }
        }
        return e;
}

Proces powraca 0niezależnie od używanego pliku.

chb
źródło
Skąd wiesz, że to nie zadziałało? Co powiesz dulub du -hpowiesz? Czy to możliwe, że plik jest plikiem rzadkim?
Mikel
2
Jaki jest cel dołączenia licencji do tego postu? Wydaje się, że to tylko hałas.
Mikel
du -h /tmp/file.logwyniki w11G /tmp/file.log
chb
@Mikel Podałem licencję jako uprzejmość ... zauważysz, że zredagowałem większość z nich.
chb
1
licencja jest rozrywką, prawdziwy klejnot tutaj jest odpowiedzią
iruvar

Odpowiedzi:

12

cat /dev/nulljest nieco skomplikowanym sposobem na napisanie polecenia, które nie generuje danych wyjściowych. :lub truesą bardziej oczywiste.

We wszystkich cat /dev/null > file, : > filea nawet > filew większości powłok, powłoka otwiera plik z użycia znacznika O_TRUNC na standardowe wyjście, a następnie uruchamia aplikację, która nie ma nic wyjściowej, a następnie plik zostanie zamknięty i lewo obcięty.

Jednak w takim przypadku lub podczas korzystania z truncatewywołania systemowego, jeśli proces wypełniający ten plik nie otworzył go flagą O_APPEND, następnym razem zapisze się w deskryptorze pliku, który ma w pliku, zapisze dane z przesunięciem znajdowały się w pliku.

Ponieważ HFS + nie obsługuje plików rzadkich, oznacza to, że przestrzeń przed tym przesunięciem będzie musiała zostać ponownie przydzielona i wypełniona zerami przez system.

Musisz więc zabić aplikację, która pisze do tego pliku, zanim go obetniesz. Lub musisz upewnić się, że aplikacja otwiera plik za pomocą O_APPEND(podobnie jak w >>przypadku korzystania z przekierowania powłoki).

Jeśli chcesz z tym eksperymentować:

$ exec 3> x
$ yes | head -n 50000 >&3
$ ls -ls x
200 -rw-r--r--  1 me me  100000 Dec 16 21:32 x

Teraz fd 3 mojej powłoki ma 100 000 bajtów w pliku

$ : > x
$ ls -ls x
0 -rw-r--r--  1 me me  0 Dec 16 21:34 x

Teraz plik jest obcinany (rozmiar 0, brak miejsca na dysku).

$ echo >&3
$ ls -ls x
200 -rw-r--r--  1 me me  100001 Dec 16 21:34 x

Zapisując 1 bajt do pliku z przesunięciem 100000, plik ma teraz 100001 bajtów, pierwsze zera wszystkie, zużyłyby ponad 100 000 na HFS +, ale około jednego bloku dysku w większości innych systemów plików Unix

Z drugiej strony:

$ exec 3>> x
$ yes | head -n 50000 >&3
$ ls -ls x
200 -rw-r--r--  1 me me  100000 Dec 16 21:35 x
$ : > x
$ echo >&3
$ ls -ls x
8 -rw-r--r--  1 me me  1 Dec 16 21:36 x

Zapis 1 bajtu do pliku nie z przesunięciem 100000, ale na końcu pliku z powodu O_APPEND. Plik ma 1 bajt i zajmuje miejsce potrzebne do przechowywania tego jednego bajtu.

Stéphane Chazelas
źródło
1
Wiele się nauczyłem z tej odpowiedzi. Dzięki.
rozdz.