标签: 文件

  • 使用stdbuf解决tail -f加管道命令后不能及时输出的问题(IO缓冲的坑)

    一般我们使用tail -f来跟踪文件变化(或tail -F来对付轮转日志)。

    但是在tail加上管道(例如tail -f | xxcmd )后,会发现输出可能有延时,
    就是说,日志文件变化了,但管道命令并没有及时输出结果。要等到日志
    变化达到一定量时才输出。

    发生这种现象,就是因为IO缓冲机制造成的。
    缓冲是一种有效提高IO效率的方法,把频繁的读写请求积累到一定程度后再
    一次性的与IO设备交互操作。

    IO缓冲有3种,无缓冲,行缓冲,和全缓冲。

    无缓冲,就是不使用缓冲机制。面向字节的设备?(stderr)
    行缓冲,缓冲,直到遇到换行符。一般用于终端设备。
    全缓冲,缓冲,直到buffer满。一般用于块设备。

    在终端窗口中执行tail命令,是面向终端设备的,会使用行缓冲,
    所以日志中每写入一行,立刻就会输出。
    当使用管道时,会变为使用全缓冲,这样一来,就要等到日志中
    写入的字节数填满buffer后才会输出。

    tail命令是如何判断,如何转换缓冲方式的,还没有来的及研究,
    根据下面的实验现象,
    tail -f加grep或sed,没有问题。但再加一层管道,就有问题。
    tail -f加awk,有问题。

    先记录一下几种解决方法。
    一,使用stdbuf命令。它是coreutils包中的命令,一般系统都已安装。
    它可以修改命令的缓冲方式。
    例如 stdbuf -oL tail 就把tail的输出设置为行缓冲。

    但是,有些命令,在命令中自己会设置缓冲方式,这就会覆盖stdbuf的设置。
    还有一些命令是不使用流(stream)的(像cat和dd),stdbuf对他们无效。

    二,把tail的标准输出重定向到标准错误上,并把标准错误也给管道。
    因为stderr是无缓冲的。
    例如 tail -f file.log >&2 | grep abc | python ok.py

    实验结果:

    a.log是另一个进程每秒写入的。

    $ tail -fn0 a.log
    2016/06/17 22:52:08
    ^C
    $ tail -fn0 a.log |grep .
    2016/06/17 22:52:12
    ^C
    $ tail -fn0 a.log |grep .|grep .
    ^C
    $ stdbuf -oL tail -fn0 a.log |grep .|grep .
    ^C
    $ stdbuf -oL tail -fn0 a.log |stdbuf -oL grep .|grep .
    2016/06/17 22:52:34
    2016/06/17 22:52:35
    ^C
    $ tail -fn0 a.log |stdbuf -oL grep .|grep .
    2016/06/17 22:53:01
    2016/06/17 22:53:02
    2016/06/17 22:53:03
    ^C
    $ tail -fn0 a.log |grep .|grep .
    ^C
    $ tail -fn0 a.log |grep .|stdbuf -oL grep .
    ^C
    $ tail -fn0 a.log >&2 |& grep .|grep .
    2016/06/17 22:53:45
    2016/06/17 22:53:46
    ^C
    $ tail -fn0 a.log|awk '{print}'
    ^C
    

    转载请注明:爱开源 » 使用stdbuf解决tail -f加管道命令后不能及时输出的问题(IO缓冲的坑)

  • Linux中find常见用法示范以及删除7天前的文件

    Linux中find常见用法示例以及删除7天前的文件
    ·find path -option [ -print ] [ -exec -ok command ] {} \;

    find命令的参数;

    pathname: find命令所查找的目录路径。例如用.来表示当前目录,用/来表示系统根目录。
    -print: find命令将匹配的文件输出到标准输出。
    -exec: find命令对匹配的文件执行该参数所给出的shell命令。相应命令的形式为’command’ { } \;,注意{ }和\;之间的空格。
    -ok: 和-exec的作用相同,只不过以一种更为安全的模式来执行该参数所给出的shell命令,在执行每一个命令之前,都会给出提示,让用户来确定是否执行。

    #-print 将查找到的文件输出到标准输出
    #-exec command {} \; —–将查到的文件执行command操作,{} 和 \;之间有空格
    #-ok 和-exec相同,只不过在操作前要询用户
    例:find . -name .svn | xargs rm -rf
    ====================================================
    -name filename #查找名为filename的文件
    -perm #按执行权限来查找
    –user username #按文件属主来查找
    -group groupname #按组来查找
    -mtime -n +n #按文件更改时间来查找文件,-n指n天以内,+n指n天以前
    -atime -n +n #按文件访问时间来查GIN: 0px”>

    -ctime -n +n #按文件创建时间来查找文件,-n指n天以内,+n指n天以前

    -nogroup #查无有效属组的文件,即文件的属组在/etc/groups中不存在
    -nouser #查无有效属主的文件,即文件的属主在/etc/passwd中不存
    -newer f1 !f2 找文件,-n指n天以内,+n指n天以前
    -ctime -n +n #按文件创建时间来查找文件,-n指n天以内,+n指n天以前
    -nogroup #查无有效属组的文件,即文件的属组在/etc/groups中不存在
    -nouser #查无有效属主的文件,即文件的属主在/etc/passwd中不存
    -newer f1 !f2 #查更改时间比f1新但比f2旧的文件
    -type b/d/c/p/l/f #查是块设备、目录、字符设备、管道、符号链接、普通文件
    -size n[c] #查长度为n块[或n字节]的文件
    -depth #使查找在进入子目录前先行查找完本目录
    -fstype #查更改时间比f1新但比f2旧的文件
    -type b/d/c/p/l/f #查是块设备、目录、字符设备、管道、符号链接、普通文件
    -size n[c] #查长度为n块[或n字节]的文件
    -depth #使查找在进入子目录前先行查找完本目录
    -fstype #查位于某一类型文件系统中的文件,这些文件系统类型通常可 在/etc/fstab中找到
    -mount #查文件时不跨越文件系统mount点
    -follow #如果遇到符号链接文件,就跟踪链接所指的文件
    -cpio %; #查位于某一类型文件系统中的文件,这些文件系统类型通常可 在/etc/fstab中找到
    -mount #查文件时不跨越文件系统mount点
    -follow #如果遇到符号链接文件,就跟踪链接所指的文件
    -cpio #对匹配的文件使用cpio命令,将他们备份到磁带设备中
    -prune #忽略某个目录
    =====================================================
    $find ~ -name “.txt” -print #在$HOME中查.txt文件并显示
    $find . -name “
    .txt” -print
    $find . -name “[A-Z]” -print #查以大写字母开头的文件
    $find /etc -name “host
    ” -print #查以host开头的文件
    $find . -name “[a-z][a-z][0–9][0–9].txt” -print #查以两个小写字母和两个数字开头的txt文件
    $find . -perm 755 -print
    $find . -perm -007 -exec ls -l {} \; #查所有用户都可读写执行的文件同-perm 777
    $find . -type d -print
    $find . ! -type d -print
    $find . -type l -print

    $find . -size +1000000c -print #查长度大于1Mb的文件
    $find . -size 100c -print # 查长度为100c的文件
    $find . -size +10 -print #查长度超过期作废10块的文件(1块=512字节)

    $cd /
    $find etc home apps -depth -print | cpio -ivcdC65536 -o /dev/rmt0
    $find /etc -name “passwd” -exec grep “cnscn” {} \; #看是否存在cnscn用户
    $find . -name “yao
    ” | xargs file
    $find . -name “yao” | xargs echo “” > /tmp/core.log
    $find . -name “yao
    ” | xargs chmod o-w

    ======================================================

    find -name april 在当前目录下查找以april开始的文件
    find -name april
    fprint file 在当前目录下查找以april开始的文件,并把结果输出到file中
    find -name ap -o -name may 查找以ap或may开头的文件
    find /mnt -name tom.txt -ftype vfat 在/mnt下查找名称为tom.txt且文件系统类型为vfat的文件
    find /mnt -name t.txt ! -ftype vfat 在/mnt下查找名称为tom.txt且文件系统类型不为vfat的文件
    find /tmp -name wa* -type l 在/tmp下查找名为wa开头且类型为符号链接的文件
    find /home -mtime -2 在/home下查最近两天内改动过的文件
    find /home -atime -1 查1天之内被存取过的文件
    find /home -mmin +60 在/home下查60分钟前改动过的文件
    find /home -amin +30 查最近30分钟前被存取过的文件
    find /home -newer tmp.txt 在/home下查更新时间比tmp.txt近的文件或目录
    find /home -anewer tmp.txt 在/home下查存取时间比tmp.txt近的文件或目录
    find /home -used -2 列出文件或目录被改动过之后,在2日内被存取过的文件或目录
    find /home –user cnscn 列出/home目录内属于用户cnscn的文件或目录
    find /home -uid +501 列出/home目录内用户的识别码大于501的文件或目录
    find /home -group cnscn 列出/home内组为cnscn的文件或目录
    find /home -gid 501 列出/home内组id为501的文件或目录
    find /home -nouser 列出/home内不属于本地用户的文件或目录
    find /home -nogroup 列出/home内不属于本地组的文件或目录
    find /home -name tmp.txt -maxdepth 4 列出/home内的tmp.txt 查时深度最多为3层
    find /home -name tmp.txt -mindepth 3 从第2层开始查
    find /home -empty 查找大小为0的文件或空目录
    find /home -size +512k 查大于512k的文件
    find /home -size -512k 查小于512k的文件
    find /home -links +2 查硬连接数大于2的文件或目录
    find /home -perm 0700 查权限为700的文件或目录
    find /tmp -name tmp.txt -exec cat {} \;
    find /tmp -name tmp.txt -ok rm {} \;

    find / -amin -10 # 查找在系统中最后10分钟访问的文件
    find / -atime -2 # 查找在系统中最后48小时访问的文件
    find / -empty # 查找在系统中为空的文件或者文件夹
    find / -group cat # 查找在系统中属于 groupcat的文件
    find / -mmin -5 # 查找在系统中最后5分钟里修改过的文件
    find / -mtime -1 #查找在系统中最后24小时里修改过的文件
    find / -nouser #查找在系统中属于作废用户的文件
    find / –user fred #查找在系统中属于FRED这个用户的文件
    =============================================================================
    在/ l o g s目录中查找更改时间在7日以前的文件并删除它们:
    $ find logs/ -type f -mtime +7 -exec rm -f {} \;
    在/ l o g s目录中查找更改时间在7日以内的文件并删除它们:
    $ find logs/ -type f -mtime -7 -exec rm -f {} \;
    然后加入的计划任务中每日执行便可

    相关文章

    转载请注明:爱开源 » Linux中find常见用法示范以及删除7天前的文件

  • 通过loop方式挂载raw格式镜像

    虚拟机的镜像可以直接通过loop的方式来进行挂载,这种方式你必须先计算出镜像中每个分区的偏移量(fdisk -lu可查看),然后通过loop的方式的挂载,加上偏移量

    这个方式的镜像必须是Raw格式的。

    root@aikaiyuan-pc:/media/aikaiyuan/虚拟文件# qemu-img info Linux-aikaiyuan.raw
    image: Linux-aikaiyuan.raw
    file format: raw
    virtual size: 30G (32212254720 bytes)
    disk size: 30G
    

    详细命令如下

    root@aikaiyuan-pc:/media/aikaiyuan/虚拟文件# fdisk -lu Linux-aikaiyuan.raw
    Disk Linux-aikaiyuan.raw: 30 GiB, 32212254720 bytes, 62914560 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: dos
    Disk identifier: 0x00064f45
    
    Device Boot Start End Sectors Size Id Type
    Linux-aikaiyuan.raw1 *   2048 411647 409600 200M 83 Linux
    Linux-aikaiyuan.raw2     411648 1460223 1048576 512M 82 Linux swap / Solaris
    Linux-aikaiyuan.raw3     1460224 62914559 61454336 29.3G 83 Linux
    

    挂载 /boot 分区

    root@aikaiyuan-pc:/media/aikaiyuan/虚拟文件# mount -o loop,offset=$((2048 * 512)) Linux-aikaiyuan.raw /mnt/boot/
    

    挂载 根 分区

    root@aikaiyuan-pc:/media/aikaiyuan/虚拟文件# mount -o loop,offset=$((1460224 * 512)) Linux-aikaiyuan.raw /mnt/boot/
    

    当然你也可以通过kpartx的方式进行挂载,挂载RAW,qcow2虚拟磁盘

    转载请注明:爱开源 » 通过loop方式挂载raw格式镜像

  • linux bash判断文件或文件夹是否存在

    在写shell脚本的时候,还是有些注意事项的,比如。。空格,给变量赋值不能有空格,象a=1就不能写成a = 1,刚开始的时候好纠结。。

    写判断语句的时候[]之间一定要有空格。以下是一些常见的判断:

    #shell判断文件夹是否存在
    
    #如果文件夹不存在,创建文件夹
    if [ ! -d "/myfolder" ]; then
      mkdir /myfolder
    fi
    
    #shell判断文件,目录是否存在或者具有权限
    
    folder="/var/www/"
    file="/var/www/log"
    
    # -x 参数判断 $folder 是否存在并且是否具有可执行权限
    if [ ! -x "$folder"]; then
      mkdir "$folder"
    fi
    
    # -d 参数判断 $folder 是否存在
    if [ ! -d "$folder"]; then
      mkdir "$folder"
    fi
    
    # -f 参数判断 $file 是否存在
    if [ ! -f "$file" ]; then
      touch "$file"
    fi
    
    # -n 判断一个变量是否有值
    if [ ! -n "$var" ]; then
      echo "$var is empty"
      exit 0
    fi
    
    # 判断两个变量是否相等
    if [ "$var1" = "$var2" ]; then
      echo '$var1 eq $var2'
    else
      echo '$var1 not eq $var2'
    fi
    

    转载请注明:爱开源 » linux bash判断文件或文件夹是否存在

  • python read() readline() readlines() write() writelines()

    open()成功执行后返回一个文件对象,以后所有对该文件的操作都可以通过这个“句柄”来进行,现在主要讨论下常用的输入以及输出操作。

    输出:

    read()方法用于直接读取字节到字符串中,可以接参数给定最多读取的字节数,如果没有给定,则文件读取到末尾。

    readline()方法读取打开文件的一行(读取下个行结束符之前的所有字节),然后整行,包括行结束符,作为字符串返回。

    readlines()方法读取所有行然后把它们作为一个字符串列表返回

    eg:

    文件/root/2.txt的内容如下,分别使用上面的三个方法来读取,注意区别:

    read():

    cat /root/2.txt
    
    I’ll write this message for you
    hehe,that’s will be ok.
    
    >>>>fobj = open(‘/root/2.txt’)    ##默认已只读方式打开
    
    >>>>a = fobj.read()
    
    >>>>a
    
    “I’ll write this message for younhehe,that’s will be ok.n”   ##直接读取字节到字符串中,包括了换行符
    
    >>>> print a
    
    I’ll write this message for you
    hehe,that’s will be ok.
    
    >>>>fobj.close()    ##关闭打开的文件
    

    readline():

    >>>> fobj = open(‘/root/2.txt’)
    
    >>>>b  = fobj.readline()
    
    >>>>b
    
    “I’ll write this message for youn”    ##整行,包括行结束符,作为字符串返回
    
    >>>>c = fobj.readline()
    
    c
    
    >>>>”hehe,that’s will be ok.n”      ##整行,包括行结束符,作为字符串返回
    
    >>>>fobj.close()
    

    readlines():

    >>>>fobj = open(‘/root/2.txt’)
    
    >>>> d = fobj.readlines()
    
    >>>>d
    
    ["I'll write this message for youn", "hehe,that's will be ok.n"]    ##读取所有行然后把它们作为一个字符串列表返回
    
    >>>>fobj.close()
    

    输入:

    write()方法和read()、readline()方法相反,将字符串写入到文件中。

    和readlines()方法一样,writelines()方法是针对列表的操作。它接收一个字符串列表作为参数,将他们写入到文件中,换行符不会自动的加入,因此,需要显式的加入换行符。

    eg:

    write():

    >>> >fobj = open(‘/root/3.txt’,’w’)      ###确保/root/3.txt没有存在,如果存在,则会首先清空,然后写入。
    >>> >msg = ['write date','to 3.txt','finish']    ###这里没有显式的给出换行符
    >>> >for m in msg:
    …            fobj.write(m)
    …
    >>> >fobj.close()
    
    cat /root/3.txt
    
    write dateto 3.txtfinish
    
    >>>>fobj = open(‘/root/3.txt’,’w’)    ###覆盖之前的数据
    
    >>>>msg = ['write daten','to 3.txtn','finishn']     ###显式给出换行符
    
    >>> >for m in msg:
    …            fobj.write(m)
    …
    >>> >fobj.close()
    
    cat /root/3.txt
    
    write date
    to 3.txt
    finish
    

    writelines():

    >>>>fobj = open(‘/root/3.txt’,’w’)
    
    >>>>msg = ['write daten','to 3.txtn','finishn']
    
    >>>>fobj.writelines(msg)
    
    >>>>fobj.close()
    
    cat /root/3.txt
    
    write date
    to 3.txt
    finish
    

    转载请注明:爱开源 » python read() readline() readlines() write() writelines()

  • nginx apache 禁止指定目录 执行PHP文件

    Nginx

    location /upload/ {
        location ~ .*.(php)?$
        {
            deny all;
        }
    }
    
    location ~* ^/(upload|images)/.*.(php|php5)$
    {
        deny all;
    }
    

    Apache

    <Directory /webroot/attachments>
        php_flag engine off
    </Directory>
    

    转载请注明:爱开源 » nginx apache 禁止指定目录 执行PHP文件

  • nginx 301重定向配置

    301重定向不陌生, 有时候有需求把某目录整个重定向到一个二级域名,或者不带www的顶级域名请求全部重定向到带www的二级域名.如果是Apache,需要配置.htaccess,nginx不支持,需要在配置文件里面使用rewrite指令来实现。

    顶级域名重定向到www

    server {
     server_name ttlsa.com;
     rewrite ^/(.*)$ http://www.ttlsa.com/$1 permanent;
     }
    

    如上配置,所以ttlsa.com的请求都会重定向到www.ttlsa.com,301重定向对SEO很有帮助.这个配置大家用的最多。

    www二级域名重定向到顶级域名

    server {
     server_name www.ttlsa.com;
     rewrite ^/(.*)$ http://domain.com/$1 permanent;
     }
    

    江湖盛传顶级域名的权重会比www二级域名的权重高,有些seoer会要求运维一定要把www的请求转到顶级域名,和上面的做法相反。

    目录重定向

    if ( $request_filename ~ nginxjiaocheng/ ) {
     rewrite ^ http://www.ttlsa.com/nginx/? permanent;
     }
    

    目录跳转新域名

    if ( $request_filename ~ nginx/ ) {
     rewrite ^ http://nginx.ttlsa.com/? permanent;
     }
    

    nginx这个栏目太火了,打算专门弄一个域名。

    转载请注明:爱开源 » nginx 301重定向配置

  • python 多线程日志切割+日志分析

    楼主最近刚刚接触python,还是个小菜鸟,没有学习python之前可以说楼主的shell已经算是可以了,但用shell很多东西实现起来还是不可能的事情,例如最明显的一点大日志分析,由于楼主的公司,每天的日志量很大,用shell分析的会非常非常的慢。

    通过学习python,楼主有了一种想法,想法如下

    可不可以分割日志,把日志分割成很多的小块,利用多线程去分析日志,这个难点在哪,难点就在如何去分割日志,前几篇文件楼主写过日志分割的python版,但是存在很大的弊端,只能够针对小日志进行分割,因为上一篇是把日志先写到列表中,大家都知道列表时要站内存的,那如果说日志很大,岂不一下就把内存吃满了。废话就不多说了,楼主来阐明下如何解决此问题

    首先创建一个文本,文本内容如下

    1
    2
    3
    .
    .
    .
    1000
    

    1.计算出文本一行的大小比如说是4B

    2.用服务器的总内存数除以4B 计算出我的服务器可以一次性分析多大的文件,这个数就是我一个文本应该为多少行,也就是说我切割的日志,一个文件是多少行

    下面奉献出日志切割的脚本

    #!/usr/bin/python
    from time import ctime
    def splitFile(fileLocation, targetFoler):
       file_handler = open(fileLocation, 'r')
       block_size = 100   (为我每个文件的行数)
       line = file_handler.readline()
       temp = []
       countFile = 1
       while line:
           for i in range(block_size):
               if i == (block_size-1):
                   # write block to small files
                   file_writer = open(targetFoler + "file_"+str(countFile)+".txt", 'a+')
                   file_writer.writelines(temp)
                   file_writer.close()
                   temp = []
                   print "  file " + str(countFile) + " generated at: " + str(ctime())
                   countFile = countFile + 1
               else:
                   temp.append(file_handler.readline())
           if countFile == 11:
                   break;
    
       file_handler.close()
    
    if __name__ == '__main__':
       print "Start At: " + str(ctime())
       splitFile("/home/python/test.txt", "/tmp/")
    

    分割完日志后,下面就该进行日志分析了

    #!/usr/bin/python
    import os
    import re
    import threading
    def chaFile(path):
           a=os.listdir(path)
           for i in range(len(a)):
                   b=a[i]
                   c=open("/home/python/rizhifenge.txt","a+")
                   kk="n"+b
                   c.writelines(kk)
                   c.close()
           d=open("/home/python/rizhifenge.txt","r")
           f=d.read()
           e=re.findall("file.*",f)
           return e
           d.close()
    
    def chaZhao(path):
           aa=open(path,"r+")
           bb=aa.read()
           cc=re.search("d.",bb)
           if cc:
                   print cc.group()
           aa.close()
    
    if __name__ == "__main__":
           ff="/tmp/"
           for i in chaFile(ff):
                   gg=ff+i
                   a=threading.Thread(target=chaZhao,args=(gg,))
                   a.start()
    

    转载请注明:爱开源 » python 多线程日志切割+日志分析

  • tailf and tail -f

    缘起

    有一个日志文件,很大很大;当想看最新的写入的时候,首先想到的是tailf,大概是因为 tailf 比 tail -f 少2个字符吧。但是,许久没有输出,感觉不应该的,不管文件有多大,从文件尾部开始查还是比较快的;换用tail -f 试试,很快就出结果了。

    下面就谈谈二者的区别:

    1. tailf 总是从文件开头一点一点的读, 而tail -f 则是从文件尾部开始读

    2. tailf check文件增长时,使用的是文件名, 用stat系统调用;而tail -f 则使用的是已打开的文件描述符; 注:tail 也可以做到类似跟踪文件名的效果; 但是tail总是使用fstat系统调用,而不是stat系统调用;结果就是:默认情况下,当tail的文件被偷偷删除时,tail是不知道的,而tailf是知道的。

    关于stat & fstat

    fstat与 stat() 函数相似,不同的是,它是作用于已打开的文件指针而不是文件名

    关于 tail -F filename

    -F filename 是跟踪文件名,当文件被删除或被重新创建是可以立即(伪立即)发现的。实现逻辑如下:

    如果filename被打开了,不是每次都重新打开文件,而是用fstat检查文件是否变化,隔几次才使用open方法检查文件是否还在,如果成功打开了,则fstat检查一下是否依然是原来的那个文件,如果是,则直接关闭本次的文件描述符,依然使用原来的监视;如果不是,则开始监视新的文件,strace跟踪如下:

    strace -F a

    open("a", O_RDONLY|O_NONBLOCK)          = 3
    fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    lseek(3, 0, SEEK_SET)                   = 0
    nanosleep({1, 0}, NULL)                 = 0
    fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    read(3, "an", 8192)                    = 2
    write(1, "an", 2a
    )                      = 2
    read(3, "", 8192)                       = 0
    fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    nanosleep({1, 0}, NULL)                 = 0
    fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    nanosleep({1, 0}, NULL)                 = 0
    fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    nanosleep({1, 0}, NULL)                 = 0
    fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    nanosleep({1, 0}, NULL)                 = 0
    fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    nanosleep({1, 0}, NULL)                 = 0
    fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    open("a", O_RDONLY|O_NONBLOCK)          = 4
    fstat(4, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    close(4)                                = 0
    nanosleep({1, 0}, NULL)                 = 0
    fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    nanosleep({1, 0}, NULL)                 = 0
    fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    nanosleep({1, 0}, NULL)                 = 0
    

    tail -retry 选项是干啥的

    默认情况下, tail -f filename 当filename不存在时,则直接退出; 但是,如果使用-retry选项,则会不断尝试打开该文件,而不是直接退出,这在有时候是有用的

    strace tailf

    open("a", O_RDONLY)                     = 3
    fstat(3, {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2af8e0b98000
    read(3, "an", 4096)                    = 2
    read(3, "", 4096)                       = 0
    fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2af8e0b99000
    write(1, "an", 2a
    )                      = 2
    stat("a", {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    stat("a", {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    nanosleep({0, 250000000}, NULL)         = 0
    stat("a", {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    nanosleep({0, 250000000}, NULL)         = 0
    stat("a", {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    nanosleep({0, 250000000}, NULL)         = 0
    stat("a", {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    nanosleep({0, 250000000}, NULL)         = 0
    stat("a", {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    nanosleep({0, 250000000}, NULL)         = 0
    stat("a", {st_mode=S_IFREG|0664, st_size=2, ...}) = 0
    nanosleep({0, 250000000}, NULL)         = 0
    

    参考资料:

    http://codingstandards.iteye.com/blog/832760

    转载请注明:爱开源 » tailf and tail -f

  • Linux文件空洞与稀疏文件

    1、Linux文件空洞与稀疏文件

    2、文件系统数据存储

    3、文件系统调试

    文件空洞

    1. 在UNIX文件操作中,文件位移量可以大于文件的当前长度
      在这种情况下,对该文件的下一次写将延长该文件,并在文件中构成一个空洞。位于文件中但没有写过的字节
      都被设为 0。
    2. 如果 offset 比文件的当前长度更大,下一个写操作就会把文件“撑大(extend)”
      在文件里创造“空洞(hole)”。
      没有被实际写入文件的所有字节由重复的 0 表示。空洞是否占用硬盘空间是由文件系统(file system)决定

    20140913144536_1

    稀疏文件(Sparse File)

    1. 稀疏文件与其他普通文件基本相同,区别在于文件中的部分数据是全0,且这部分数据不占用磁盘
      空间。
      下面是稀疏文件的创建与查看
    [root@localhost ~]# dd if=/dev/zeroof=sparse-file bs=1 count=1 seek=1024k
    [root@localhost ~]# ls -l sparse-file
    -rw-r--r-- 1 root root 1048577 Oct 15 17:50 sparse-file
    [root@localhost ~]# du -sh sparse-file
    8.0K sparse-file
    [root@localhost ~]# cat anaconda-ks.cfg >> sparse-file
    [root@localhost ~]# du -sh sparse-file
    12K sparse-file
    [root@localhost ~]# du -sh anaconda-ks.cfg
    12K anaconda-ks.cfg
    [root@localhost ~]#
    

    Linux文件系统inode数据块存储

    索引节点采用了多重索引结构,主要体现在直接指针和3个间接指针。直接指针包含12个直接指
    针块,它们直接指向包含文件数据的数据块,紧接在后面的3个间接指针是为了适应文件的大小
    变化而设计。

    20140913144536_2

    Linux稀疏文件inode数据块存储

    文件系统存储稀疏文件时,inode索引节点中,只给出实际占用磁盘空间的Block 号,
    数据全零且不占用磁盘空间的文件Block并没有物理磁盘Block号。

    20140913144536_3

    Linux稀疏文件inode数据块存储

    • 文件空洞部分不占用磁盘空间
    • 文件所占用的磁盘空间仍然是连续的

    20140913144536_4

    实例:

    [root@localhost mnt]# du -sh sparse-file
    20K sparse-file
    [root@localhost mnt]# ls -lh sparse-file
    -rw-r--r-- 1 root root 1.1G Oct 15 10:36 sparse-file
    [root@localhost mnt]#
    debugfs: stat sparse-file
    Inode: 49153 Type: regular Mode: 0644 Flags:
    0x0 Generation: 3068382963
    User: 0 Group: 0 Size: 1073742848
    File ACL: 0 Directory ACL: 0
    Links: 1 Blockcount: 40
    Fragment: Address: 0 Number: 0 Size: 0
    ctime: 0x507b76af -- Mon Oct 15 10:36:31 2012
    atime: 0x507b765f -- Mon Oct 15 10:35:11 2012
    mtime: 0x507b76af -- Mon Oct 15 10:36:31 2012
    BLOCKS:
    (IND):106496, (256):106497, (DIND):106504,
    (IND):106505, (262144):106506
    TOTAL: 5
    

    Linux文件系统数据块存储多重索引

    • Linux文件系统数据存放采用inode多
      重索引结构,有直接指针和3个间接指
      针。
      类似于编程中的变量定义:
      unsigned long blk;
      unsigned long blk;
      unsigned long
      blk;
      unsigned long
      **blk;
    • 直接指针直接指向保存数据的Block
      号。
    • 一级指针指向一个Block,该Block中
      的数据是Block指针,指向真正保存数
      据的Block。
      二级三级指针以此类推。

    20140913144536_5

    1. 前12个直接指针,直接指向存储的数据区域
      如Blocks大小为4096,则前12个直接指针就可以保存48KB文件。
    2. 一级指针可存储文件大小计算
      假设每个指针占用4个字节,则一级指针指向的Block可保存4096/4个
      指针,可指向1024个Blocks。一级指针可存储文件数据大小为1024*4096 =
      4MB。
    3. 二级指针可存储文件大小计算
      同样按照Blocks大小为4096,则二级指针可保存的Block指针数量为(4096/4) *
      (4096/4) = 10241024。则二级指针可保存的文件数量大小为(10241024)*4096
      = 4GB。
    4. 三级指针可存储文件大小计算
      以一级、二级指针计算方法类推,三级指针可存储的文件数据大小为
      (102410241024)*4096 = 4TB。

    20140913144536_6

    Linux_File_Hole_And_Sparse_Files

    转载请注明:爱开源 » Linux文件空洞与稀疏文件