一、inotifywait介绍

Inotify 一种强大的、细粒度的、异步文件系统监控机制,它满足各种各样的文件监控需要,可以监控文件系统的访问属性、读写属性、权限属性、删除创建、移动等操作,也就是可以监控文件发生的一切变化。

inotify-tools 是一个C库和一组命令行的工作,提供Linux下inotify的简单接口。inotify-tools安装后会得到inotifywait和inotifywatch这两条命令:

inotifywait命令 可以用来收集有关文件访问信息,Linux发行版一般没有包括这个命令,需要安装inotify-tools,这个命令还需要将inotify支持编译入Linux内核,好在大多数Linux发行版都在内核中启用了inotify。
inotifywatch命令 用于收集关于被监视的文件系统的统计数据,包括每个 inotify 事件发生多少次。



二、安装



2.1 开始之前需要检测系统内核是否支持inotify

方式一:使用 uname -r 命令检查Linux内核,如果低于2.6.13,就需要重新编译内核加入inotify的支持。

方式二:使用ll /proc/sys/fs/inotify命令,是否有以下三条信息输出,如果没有表示不支持。

$ ll /proc/sys/fs/inotify

total 0
-rw-r--r-- 1 root root 0 Jan 4 15:41 max_queued_events
-rw-r--r-- 1 root root 0 Jan 4 15:41 max_user_instances
-rw-r--r-- 1 root root 0 Jan 4 15:41 max_user_watches



2.2 安装步骤

可直接使用Linux系统自带的包管理工具进行安装,也可以手动从源码编译安装。



2.2.1 包管理工具进行安装

以centos系统自带等yum为例

其他Linux发行版安装方法可以参见:https://github.com/rvoicilas/inotify-tools/wiki#wiki-getting

$ yum search inotify-tools
$ yum info inotify-tools
$ sudo yum install inotify-tools



2.2.2 源码编译安装

$ wget http://github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar.gz
$ tar zxf inotify-tools-3.14.tar.gz
$ cd inotify-tools-3.14/
$ ./configure && make && make install

如果遇到以下错误

inotifywait: error while loading shared libraries: libinotifytools.so.0: cannot open shared object file: No such file or directory

解决方法:

32位系统:ln -s /usr/local/lib/libinotifytools.so.0 /usr/lib/libinotifytools.so.0
64位系统:ln -s /usr/local/lib/libinotifytools.so.0 /usr/lib64/libinotifytools.so.0



三、inotifywait 基本使用

安装完成后可简单尝试下,执行以下命令监听log.txt文件

$ inotifywait -m log.txt
# 这里 -m 参数指明持续监听,不加的话会在一个事件后退出

Setting up watches.
Watches established.
# 此时持续监听,有事件出发会输出到屏幕

然后通过其他窗口执行以下命令向log.txt文件写入内容

$ echo >> log.txt

可观察到上一个屏幕输出了,因为监听到了文件打开、修改、关闭的事件。

log.txt OPEN
log.txt MODIFY
log.txt CLOSE_WRITE,CLOSE

3.1、参数说明
3.1.1 常用参数

--timefmt 时间格式
    %y年 %m月 %d日 %H小时 %M分钟
--format 输出格式
    %T时间 %w路径 %f文件名 %e状态
 
-m 始终保持监听状态,默认触发事件即退出
-r 递归查询目录
-q 减少不必要的输出(只打印事件信息)
 
-e 定义监控的事件,可用参数:
    open   打开文件
    access 访问文件
    modify 修改文件
    delete 删除文件
    create 新建文件
    attrib 属性变更
 
--exclude <pattern> 指定要排除监控的文件/目录

3.1.2 全部参数

建议通过 man inotifywait 命令查看文档中全部参数-h,–help
输出帮助信息
@
排除不需要监视的文件,可以是相对路径,也可以是绝对路径。
–fromfile
从文件读取需要监视的文件或排除的文件,一个文件一行,排除的文件以@开头。
-m, –monitor
接收到一个事情而不退出,无限期地执行。默认的行为是接收到一个事情后立即退出。
-d, –daemon
跟–monitor一样,除了是在后台运行,需要指定–outfile把事情输出到一个文件。也意味着使用了–syslog。
-o, –outfile
输出事情到一个文件而不是标准输出。
-s, –syslog
输出错误信息到系统日志
-r, –recursive
监视一个目录下的所有子目录。
-q, –quiet
指定一次,不会输出详细信息,指定二次,除了致命错误,不会输出任何信息。
–exclude
正则匹配需要排除的文件,大小写敏感。
–excludei
正则匹配需要排除的文件,忽略大小写。
-t , –timeout
设置超时时间,如果为0,则无限期地执行下去。
-e , –event
指定监视的事件。
-c, –csv
输出csv格式。
–timefmt
指定时间格式,用于–format选项中的%T格式。
–format
指定输出格式。
%w 表示发生事件的目录
%f 表示发生事件的文件
%e 表示发生的事件
%Xe 事件以“X”分隔
%T 使用由–timefmt定义的时间格式

3.2 可监听事件

access    访问,读取文件。

modify    修改,文件内容被修改。

attrib    属性,文件元数据被修改。

move    移动,对文件进行移动操作。

create    创建,生成新文件

open    打开,对文件进行打开操作。

close    关闭,对文件进行关闭操作。

delete    删除,文件被删除。

3.3 使用示例
以监听vue项目,发现有文件变化后,执行 npm run build 命令构建代码为例

假设vue项目文件目录为: /production/sites/vue-program

根据vue项目基本目录结构,则我们需要监听该目录下的src目录,且只监听文件变化的事件

inotifywait /production/sites/vue-program/src #只监听src目录,因为package.json等文件在构建完成后也会被修改
-r #监听所有子目录文件
--timefmt '%d/%m/%y %H:%M' #时间输出格式,如果--format设置了%f,则必须指明
--format "%T %f" #输出格式
-e MODIFY #只监听文件修改事件
--exclude '^.*.swp$' #如果直接使用vim等编辑工具改动文件,会触发 .swp 临时文件的修改事件,所以我们需要排除所有正则形如 /^\.((?!\.swp$).)*$/ 的文件,但此表达式在linux中貌似不行,所以用的.*.swp

以上为了方便阅读,对每个参数换行并加了注释,整理为一行如下:

inotifywait /production/sites/vue-program/src -r --timefmt '%d/%m/%y %H:%M' --format "%T %f" -e MODIFY --exclude '^.*.swp$'

运行可以观察是我们想要的效果,那我们监听到事件后加入构建代码到指令,创建shell文件 auto_build.sh

#!/bin/bash

projectDir=/production/sites/vue-program;

while inotifywait $projectDir/src -r --timefmt '%d/%m/%y %H:%M' --format "%T %f" -e MODIFY --exclude '^.*.swp$'
do
    cd $projectDir && git pull && npm run build
done

此处由于 -m 参数会监听多个文件,所以git一次提交可能会触发多个修改事件,因此没有使用 -m ,而是通过while去触发inotifywait监听,然后等待在这里;而事件触发后再执行一遍 git pull是因为第一个文件修改事件触发后,git未必将所有文件替换完,为保证npm run build指令执行时代码全部更新,所以在此处又主动执行了一遍 git pull

之后就可以启动脚本了

nohup /bin/bash auto_build.sh >> /tmp/auto_build.log 2>&1

这样,配合crontab定时拉取代码,当前端代码文件变化后,就会自动构建了,省去了每次手动操作的繁琐和遗漏。

 

 

[root@backup ~]# inotifywait --help
inotifywait 3.14
Wait for a particular event on a file or set of files.
Usage: inotifywait [ options ] file1 [ file2 ] [ file3 ] [ ... ]
Options:
    -h|--help         Show this help text.
    @<file>           Exclude the specified file from being watched.
    --exclude <pattern>
                      Exclude all events on files matching the
                      extended regular expression <pattern>.指定排除部分文件
    --excludei <pattern>
                      Like --exclude but case insensitive.(同上,排除且忽略大小写)
    -m|--monitor      Keep listening for events forever.  Without
                      this option, inotifywait will exit after one
                      event is received.(持续监听)
    -d|--daemon       Same as --monitor, except run in the background
                      logging events to a file specified by --outfile.
                      Implies --syslog.(daemon模式)
    -r|--recursive    Watch directories recursively.(递归子目录)
    --fromfile <file>
                      Read files to watch from <file> or `-' for stdin.
    -o|--outfile <file>
                      Print events to <file> rather than stdout. (将事件输出到文件,而不是屏幕)
    -s|--syslog       Send errors to syslog rather than stderr.
    -q|--quiet        Print less (only print events).(打印事件)
    -qq               Print nothing (not even events).(不打印事件)
    --format <fmt>    Print using a specified printf-like format
                      string; read the man page for more details. (设置打印格式%T时间;%w触发事件文件所在绝对路径;%f触发事件文件名称;%e触发的事件名称;)
    --timefmt <fmt>    strftime-compatible format string for use with
                      %T in --format string.(指定输出内容,相当于将时间赋值给%T)
    -c|--csv          Print events in CSV format.
    -t|--timeout <seconds>
                      When listening for a single event, time out after
                      waiting for an event for <seconds> seconds.
                      If <seconds> is 0, inotifywait will never time out.
    -e|--event <event1> [ -e|--event <event2> ... ]
        Listen for specific event(s).  If omitted, all events are 
        listened for.(指定要监听的事件,多个事件用逗号隔开)

Exit status:
    0  -  An event you asked to watch for was received.
    1  -  An event you did not ask to watch for was received
          (usually delete_self or unmount), or some error occurred.
    2  -  The --timeout option was given and no events occurred
          in the specified interval of time.

Events:     (事件)
    access        file or directory contents were read
    modify        file or directory contents were written
    attrib        file or directory attributes changed
    close_write    file or directory closed, after being opened in
                   writeable mode
    close_nowrite    file or directory closed, after being opened in
                   read-only mode
    close        file or directory closed, regardless of read/write mode
    open        file or directory opened
    moved_to    file or directory moved to watched directory
    moved_from    file or directory moved from watched directory
    move        file or directory moved to or from watched directory
    create        file or directory created within watched directory
    delete        file or directory deleted within watched directory
    delete_self    file or directory was deleted
    unmount        file system containing file or directory unmounted

例子:

[root@nfs01 data]# inotifywait -mrq -e 'create,delete,close_write,attrib,moved_to' --timefmt '%Y-%m-%d %H:%M' --format '%T %w%f %e' /backup/
2019-06-04 10:46 /backup/test.txt CREATE
2019-06-04 10:46 /backup/test.txt ATTRIB
2019-06-04 10:46 /backup/test.txt CLOSE_WRITE,CLOSE
2019-06-04 10:47 /backup/test.txt CLOSE_WRITE,CLOSE
2019-06-04 10:47 /backup/isr DELETE
2019-06-04 10:47 /backup/me MOVED_TO