I am LAZY bones ? all linux

其实,文件也可以truncate

现在觉得,时间的流逝速度和年龄确实是成正比的。也就是说,年纪越大,就会觉得空闲时间越来越少了~
因此,本blog都大半个月没更新了,呵呵。也不能老这么沉寂下去,今天来写点东西。

熟悉数据库的朋友们都知道,大多数数据库都有个truncate指令:truncate table xxx可以把xxx表里的所有数据都删掉,但是保留表结构。其实,在有任何数据库之前,UNIX系统里就有了truncate这个命令了,当然后面的*nix里都保留了这个。可以想像,系统里的truncate命令的操作对象肯定是文件,而且此命令不仅能把文件的数据删成0字节,还可以缩减(甚至扩大)文件至指定的大小(通过 -s 选项指定文件大小值),这对于那种日志头部有些不想删除的关键信息,但后面的部分又很多很杂的情况下很有用。对于普通的日志文件,我们要清理的时候通常可以执行 > log 来清除文件的内容(这样,log文件会变成0字节),但是如果清理的同时想保留原始日志的前面4K的信息,不用truncate就会很麻烦了。

truncate的用法还是通过实战来解释吧,如下:

lily@LLY ~$ echo -n 1234567 > txt
lily@LLY ~$ cat txt
1234567lily@LLY ~$ 
lily@LLY ~$ truncate -s 4 txt
lily@LLY ~$ cat txt
1234lily@LLY ~$ 
lily@LLY ~$ ls -l txt
-rw-r--r-- 1 lily lily 4 1024 16:54 txt
lily@LLY ~$ truncate -s 1M txt
lily@LLY ~$ ls -l txt
-rw-r--r-- 1 lily lily 1048576 1024 17:17 txt
lily@LLY ~$ du txt
4	txt
lily@LLY ~$ wc -c txt
1048576 txt

这里还可以看到一个“奇怪”的现象,本来已经缩至4字节的文件,把它扩展成1M以后,ls 和 wc 的结果显示大小确实是1M,但是 du 的结果却发现大小还是4字节。这也是要注意的地方之一,这种文件称为“空洞文件”,也就是说,文件的部分内容并没有实际存在于硬盘上(即没有分配对应的inode),只是“声称”有1M的大小而已。对于不存在于硬盘上的那部分字节,如果去读的话,也是不会报错的,会读到全0的数据。
这也从另一个方面反映出ls等命令默认显示的是文件“声称”的大小,而du (disk use)默认显示的是真正的磁盘占用。这里是我以前的另外一个例子。

最后修改时间: 2010年10月24日 18:29

本文章发表于: 2010年10月24日 18:29 | 所属分类:CLI软件. | 您可以在此订阅本文章的所有评论. | 您也可以发表评论, 或从您的网站trackback.

20 个评论 关于: “其实,文件也可以truncate”

  1. Shellexy 在 2010年10月24日 19:12 说:回复

    骨头哇,
    ls -l 加参数 -s 就可以了

    • bones7456 在 2010年10月24日 19:26 说:回复

      是喽,所以我文中是“默认显示”。文末那个链接的文章里,也有说到过-s参数。

  2. 依云 在 2010年10月24日 19:46 说:回复

    那个不是4字节啦。du 默认单位是块 (block)。加参数 -h 才是字节什么的。

  3. icyomik 在 2010年10月24日 20:06 说:回复

    呵呵,每次都学到新的知识。

  4. tusooa 在 2010年10月24日 22:03 说:回复

    不用truncate也可以的.
    cp -v /tmp/test{,.orig}
    head -s4 /tmp/test.orig > /tmp/test

    • bones7456 在 2010年10月25日 09:29 说:回复

      这样不仅麻烦,而且不是原子操作,比如输出日志的进程可能还一直在频繁输出的,你这样就不方便了。何况,万一日志文件很大,没有磁盘空间来给你全量复制一份怎么办?这种情况很多,比如设置了磁盘使用90%告警,然后维护人员收到告警了,才去处理日志,想把几十G的日志复制一遍可不容易。
      你这样的话,其实 head -c4 log > /tmp/log; mv /tmp/log log 更好,当然truncate还是方便多了。

      • tusooa 在 2010年10月27日 16:39 说:回复

        保留文件前3行:
        ● perl -i -e ‘$num = 0 ; while () { $num++; last if $num > 3; print; }’ /tmp/bash/svn/co-log

  5. tusooa 在 2010年10月24日 22:05 说:回复

    head -c4 。写错了。。。

  6. hfw_1987 在 2010年10月27日 15:34 说:回复

    也就是说,文件的部分内容并没有实际存在于硬盘上(即没有分配对应的inode)

    =================
    这句话有问题吧,一个文件对应一个inode,除非有硬链接,哪有没有分配对应inode的说法?

  7. shan 在 2010年10月28日 09:16 说:回复

    学习了。

    • bones7456 在 2010年10月30日 10:08 说:回复

      哈哈,这个居然被当成了垃圾评论

  8. runcoderen 在 2010年11月07日 08:55 说:回复

    学习了啊,平时一点一滴就是很大的收获了

  9. ptubuntu 在 2010年11月09日 17:14 说:回复

    看的头都大起来了.我也好久没有更新了.

  10. 沧州seo 在 2010年11月14日 23:16 说:回复

    说实话 你说的这个我真的一点不懂,可不可以顺带点基础知识啊?

  11. 远走高飞 在 2010年11月16日 09:20 说:回复

    趁年轻时觉得空闲的时候多找点事情做。。

  12. openboy 在 2010年11月21日 19:06 说:回复

    把你整个经验技巧分类翻了一遍。收获很多。感谢~喜欢折腾Ubuntu..

  13. 百度黑板报 在 2010年11月30日 03:44 说:回复

    不错~
    就是truncate不是那么标准的命令 并不是所有的系统都默认会有

  14. Learn Python The Hard Way 学习笔记(1) | oppih 在 2010年12月08日 20:19 说:回复

    […] Shell中就有truncate方法哦,这是我GR上面读到的:其实,文件也可以truncate […]

  15. ayanmw 在 2011年05月25日 16:16 说:回复

    或许 应该sync下再试试 修改文件要同步下。

  16. Dig 在 2011年11月13日 09:41 说:回复

    truncate 是不是不能按行截取?我需要保留的绝大多数log都是可读的文本格式,按字符截取似乎不太靠谱,按行才是上策;
    所以还是习惯用head/tail之类的

发表评论