Od coreutils 7.0 existuje truncate
příkaz.
Zajímavá věc na těchto přerostlých souborech je, že prvních 128 KB nebo tak bude po zkrácení souboru zkopírováním /dev/null
samé nuly přes to. K tomu dochází, protože soubor je zkrácen na nulovou délku, ale deskriptor souboru v aplikaci stále ukazuje bezprostředně po jeho posledním zápisu. Když se znovu zapisuje, systém souborů považuje začátek souboru za všechny nulové bajty – aniž by ve skutečnosti nuly zapisoval na disk.
V ideálním případě byste měli požádat dodavatele aplikace, aby otevřel soubor protokolu s O_APPEND
vlajka. To znamená, že poté, co soubor zkrátíte, další zápis bude implicitně hledat konec souboru (což znamená zpět na nulový posun) a poté zapíše nové informace.
Tento kód upravuje standardní výstup, takže je v O_APPEND
mode a poté vyvolá příkaz daný jeho argumenty (spíše jako nice
spustí příkaz po úpravě jeho úrovně nice, neboli nohup
spustí příkaz po opravě, takže ignoruje SIGHUP).
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
static char *arg0 = "<unknown>";
static void error(const char *fmt, ...)
{
va_list args;
int errnum = errno;
fprintf(stderr, "%s: ", arg0);
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (errnum != 0)
fprintf(stderr, " (%d: %s)", errnum, strerror(errnum));
putc('\n', stderr);
fflush(0);
exit(1);
}
int main(int argc, char **argv)
{
int attr;
arg0 = argv[0];
if (argc < 2)
error("Usage: %s cmd [arg ...]", arg0);
if ((attr = fcntl(1, F_GETFL, &attr)) < 0)
error("fcntl(F_GETFL) failed");
attr |= O_APPEND;
if (fcntl(1, F_SETFL, attr) != 0)
error("fcntl(F_SETFL) failed");
execvp(argv[1], &argv[1]);
error("failed to exec %s", argv[1]);
return(1);
}
Moje testování bylo poněkud náhodné, ale jen stěží natolik, aby mě přesvědčilo, že to funguje.
Jednodušší alternativa
Billy ve své odpovědi poznamenává, že '>>
' je operátor append – a skutečně na Solaris 10 bash (verze 3.00.16(1)) používá O_APPEND
flag - čímž se výše uvedený kód stává zbytečným, jak je znázorněno ("Black JL:" je moje výzva na tomto počítači):
Black JL: truss -o bash.truss bash -c "echo Hi >> x3.29"
Black JL: grep open bash.truss
open("/var/ld/ld.config", O_RDONLY) Err#2 ENOENT
open("/usr/lib/libcurses.so.1", O_RDONLY) = 3
open("/usr/lib/libsocket.so.1", O_RDONLY) = 3
open("/usr/lib/libnsl.so.1", O_RDONLY) = 3
open("/usr/lib/libdl.so.1", O_RDONLY) = 3
open("/usr/lib/libc.so.1", O_RDONLY) = 3
open("/platform/SUNW,Ultra-4/lib/libc_psr.so.1", O_RDONLY) = 3
open64("/dev/tty", O_RDWR|O_NONBLOCK) = 3
stat64("/usr/openssl/v0.9.8e/bin/bash", 0xFFBFF2A8) Err#2 ENOENT
open64("x3.29", O_WRONLY|O_APPEND|O_CREAT, 0666) = 3
Black JL:
Spíše než výše uvedený kód wrapper ('cantrip') použijte přesměrování typu append. To jen dokazuje, že když používáte jednu konkrétní techniku pro jiné (platné) účely, její přizpůsobení dalšímu nemusí být nutně tím nejjednodušším mechanismem – i když funguje.
Přesměrujte výstup pomocí>> namísto>. To vám umožní zkrátit soubor, aniž by se soubor zvětšil zpět do své původní velikosti. Také nezapomeňte přesměrovat STDERR (2>&1).
Takže konečný výsledek by byl:myprogram >> myprogram.log 2>&1 &