在文件运行时截断文件';正在使用的(Linux)

在文件运行时截断文件';正在使用的(Linux),linux,unix,file,logging,truncate,Linux,Unix,File,Logging,Truncate,我有一个将大量数据写入stdout的进程,我将其重定向到一个日志文件。我希望通过偶尔将当前文件复制到新名称并截断来限制文件的大小 我常用的截断文件的技术,比如 cp /dev/null file 不工作,可能是因为流程正在使用它 有什么方法可以截断文件吗?或者删除它并以某种方式将进程的stdout与新文件关联 FWIW,这是一个第三方产品,我不能修改它来改变它的日志模型 编辑在文件上重定向似乎与上面的副本存在相同的问题-文件下次写入时会恢复到以前的大小: ls -l sample.log ;

我有一个将大量数据写入stdout的进程,我将其重定向到一个日志文件。我希望通过偶尔将当前文件复制到新名称并截断来限制文件的大小

我常用的截断文件的技术,比如

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