在文件运行时截断文件';正在使用的(Linux)
我有一个将大量数据写入stdout的进程,我将其重定向到一个日志文件。我希望通过偶尔将当前文件复制到新名称并截断来限制文件的大小 我常用的截断文件的技术,比如在文件运行时截断文件';正在使用的(Linux),linux,unix,file,logging,truncate,Linux,Unix,File,Logging,Truncate,我有一个将大量数据写入stdout的进程,我将其重定向到一个日志文件。我希望通过偶尔将当前文件复制到新名称并截断来限制文件的大小 我常用的截断文件的技术,比如 cp /dev/null file 不工作,可能是因为流程正在使用它 有什么方法可以截断文件吗?或者删除它并以某种方式将进程的stdout与新文件关联 FWIW,这是一个第三方产品,我不能修改它来改变它的日志模型 编辑在文件上重定向似乎与上面的副本存在相同的问题-文件下次写入时会恢复到以前的大小: ls -l sample.log ;
cp /dev/null file
不工作,可能是因为流程正在使用它
有什么方法可以截断文件吗?或者删除它并以某种方式将进程的stdout与新文件关联
FWIW,这是一个第三方产品,我不能修改它来改变它的日志模型
编辑在文件上重定向似乎与上面的副本存在相同的问题-文件下次写入时会恢复到以前的大小:
ls -l sample.log ; echo > sample.log ; ls -l sample.log ; sleep 10 ; ls -l sample.log
-rw-rw-r-- 1 user group 1291999 Jun 11 2009 sample.log
-rw-rw-r-- 1 user group 1 Jun 11 2009 sample.log
-rw-rw-r-- 1 user group 1292311 Jun 11 2009 sample.log
尝试
>文件
关于评论的更新:它对我很有效:
robert@rm:~> echo "content" > test-file
robert@rm:~> cat test-file
content
robert@rm:~> > test-file
robert@rm:~> cat test-file
查看GNU Coreutils的一部分实用程序split(1)。在使用该文件时,如果您尝试将其置零或类似的操作,有时可能会“混淆”正在写入日志文件的应用程序,并且之后可能不会记录任何内容 我会尝试为该日志设置一种代理/过滤器,而不是重定向到文件、重定向到进程或获取输入并写入滚动文件的东西 也许它可以通过脚本来完成,否则你可以为此编写一个简单的应用程序(java或其他东西)。对应用程序性能的影响应该很小,但您必须运行一些测试 顺便说一句,你的应用程序是一个独立的网络应用程序吗?也许还有其他的选择需要研究
编辑:还有一个我个人从未使用过的,但它可能不会锁定文件。您是否检查了任何信号的行为,如SIGHUP到第三方产品,以查看它是否会开始记录新文件?首先,将旧文件移动到永久名称 kill-HUP[进程id] 然后它会再次开始写出来 或者(正如Billy所建议的)可能会将应用程序的输出重定向到一个日志程序(如multilog)或Apache常用的程序(称为cronolog)。然后,在将所有内容写入初始文件描述符(文件)之前,您可以对其进行更细粒度的控制。在Linux(实际上是所有unicies)中,文件是在打开时创建的,在没有任何引用时删除的。在这种情况下,打开它的程序和它在“中”打开的目录保留对该文件的引用。当cp程序想要写入文件时,它会从目录中获取一个对该文件的引用,将长度为零的数据写入目录中存储的元数据(这是一个稍微简化的过程),并放弃句柄。然后,原始程序仍然持有原始文件句柄,将更多数据写入文件,并保存它认为应该的长度 即使要从目录中删除文件,程序也会继续向其中写入数据(并耗尽磁盘空间),即使其他程序无法引用它 简而言之,一旦程序有了一个文件的引用(句柄),你所做的一切都不会改变它
理论上,可以通过将LD_LIBRARY_PATH设置为包含一个拦截所有文件访问系统调用的程序来修改程序行为。我记得在某处见过这样的东西,虽然我记不起它的名字 这些重新生成文件的有趣之处在于,通过在文件上复制
/dev/null
来截断该文件后,大约前128 KB将全部为零。这是因为文件被截断为零长度,但应用程序中的文件描述符仍然在最后一次写入后立即指向。当它再次写入时,文件系统会将文件的开头视为所有零字节,而不会实际将零写入磁盘
理想情况下,您应该要求应用程序的供应商使用O\u APPEND
标志打开日志文件。这意味着在截断文件后,下一次写入将隐式地查找到文件的末尾(意味着返回偏移量为零),然后写入新信息
此代码装配标准输出,使其处于
O_APPEND
模式,然后调用其参数给出的命令(类似于nice
在调整其nice级别后运行命令,或者nohup
在修复后运行命令,以便忽略SIGHUP)
使用追加重定向而不是上面的包装器(“”)代码。这表明,当您将一种特定技术用于其他(有效)目的时,使其适应另一种技术并不一定是最简单的机制,即使它可以工作。您可以通过管道将其传送到一个程序,通过关闭该程序自动旋转该文件,而不是将其重定向到一个文件,每次它变得太大时,移动它并打开一个新的 从coreutils 7.0开始,有一个
truncate
命令。我下载并编译了最新的coreutils
,因此我可以使用truncate
运行了/configure
和make
,但未运行make install
所有编译的实用程序都显示在“src”文件夹中
我跑
[path]/src/truncate-s 1024000 textfiledineedtoruncate.log
在1.7 GB日志文件上
在使用ls-l
时,它没有更改列出的大小,但它确实释放了所有磁盘空间-这是我在/var
填满并终止进程之前真正需要做的
谢谢你关于“截断”的提示 @Hobo使用freopen(),它重用流来打开文件名指定的文件或更改其访问模式。
如果指定了新的文件名,函数将首先尝试关闭已与流关联的任何文件(第三个参数)并解除其关联。然后,独立
#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);
}
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:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <unistd.h>
#include <string.h>
using namespace std;
extern "C" void * proxyrun(void * pArg){
static int lsiLineNum = 0;
while(1)
{
printf("\nLOGGER: %d",++lsiLineNum);
fflush(stdout);
}
return NULL;
}
int main(int argc, char **argv)
{
pthread_t lThdId;
if(0 != pthread_create(&lThdId, NULL, proxyrun, NULL))
{
return 1;
}
char lpcFileName[256] = {0,};
static int x = 0;
while(1)
{
printf("\n<<<MAIN SLEEP>>>");
fflush(stdout);
sprintf(lpcFileName, "/home/yogesh/C++TestPrograms/std.txt%d",++x);
freopen(lpcFileName,"w",stdout);
sleep(10);
}
return 0;
}
echo " " > file
* * * * * my_script >> /var/log/my_script.log 2>&1
* * * * * my_script >> /var/log/my_script.log 2>/var/log/my_script.err