这些重新增长的文件的有趣之处在于,在您通过复制文件截断文件后,前 128 KB 左右将全为零/dev/null
。发生这种情况是因为文件被截断为零长度,但应用程序中的文件描述符在最后一次写入后仍立即指向。当它再次写入时,文件系统将文件的开头视为所有零字节 - 而不实际将零写入磁盘。
理想情况下,您应该要求应用程序的供应商打开带有O_APPEND
标志的日志文件。这意味着在您截断文件后,下一次写入将隐式查找文件末尾(意味着回到偏移量零),然后写入新信息。
此代码装配标准输出,使其处于O_APPEND
模式,然后调用由其参数给出的命令(就像nice
在调整其 nice 级别后nohup
运行命令,或者在修复问题后运行命令以忽略 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);
}
我对它的测试有点随意,但仅足以说服我它有效。
更简单的选择
比利在他的回答中指出 ' >>
' 是附加运算符 - 事实上,在 Solaris 10 上,bash(版本 3.00.16(1))确实使用了该O_APPEND
标志 - 从而使上面的代码变得不必要,如图所示('Black JL:'是我在这台机器上的提示):
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:
使用附加重定向而不是上面的包装器(' cantrip ')代码。这只是表明,当您将一种特定技术用于其他(有效)目的时,使其适应另一种技术不一定是最简单的机制——即使它有效。