如何使用bash监视目录中新创build的文件?

我有一个由大量日志文件组成的日志目录,一旦系统事件发生,就会创build一个日志文件。 我想写一个总是监视文件列表并在terminal上显示新创build文件的内容的online bash脚本。 这是它的样子:

目前,我所拥有的只是显示整个目录的内容:

for f in *; do cat $f; done 

它缺乏我想要的监视function。 我的系统的一个局限是我没有 watch命令。 我也没有任何包pipe理器来安装花哨的工具。 原始的BSD是我所有的。 我有tail ,我正在想像tail -F $(ls)但这尾巴每个文件,而不是文件列表。

总之,我想修改我的脚本,以便我可以监视所有新创build的文件的内容。

Solutions Collecting From Web of "如何使用bash监视目录中新创build的文件?"

  1. 第一种方法 – 在你的dir中使用隐藏文件(在我的例子中它有一个名字.watch )。 那么你的单线可能看起来像:

     for f in $(find . -type f -newer .watch); do cat $f; done; touch .watch 
  2. 第二种方法 – 使用inotify-tools: https : //unix.stackexchange.com/questions/273556/when-a-particular-file-arrives-then-execute-a-procedure-using-shell-script/273563#273563

如果你愿意的话,你可以把它塞进一行,但是我建议在后台运行这个脚本:

 #!/bin/bash [ ! -d "$1" ] && { printf "error: argument is not a valid directory to monitory.\n" exit 1 } while :; fname="$1/$(inotifywait -q -e modify -e create --format '%f' "$1")"; do cat "$fname" done 

它将监视作为第一个参数给出的目录,并cat该目录中的任何新的或更改的文件。 例:

 $ bash watchdir.sh my_logdir & 

然后在my_logdirmy_logdir新的或更改的文件。

监视模式下使用inotifywait

首先这个小演示:

  1. 打开一个终端并运行这个:

     ext=(php css other) while :;do subname='' ((RANDOM%10))||printf -v subname -- "-%04x" $RANDOM date >/tmp/test$subname.${ext[RANDOM%3]} sleep 1 done 

    这会随机创建一个名为/tmp/test.php/tmp/test.other文件,但随机地(约1次/ 10),名称将是/tmp/test-XXXX.[css|php|other]其中XXXX是一个十六进制的随机数。

  2. 打开另一个终端并运行:

     waitPaths=(/{home,tmp}) while read file ;do if [ "$file" ] && ( [ -z "${file##*.php}" ] || [ -z "${file##*.css}" ] ) ;then (($(stat -c %Y-%X $file)))||echo -n new echo file: $file, content: cat $file fi done < <( inotifywait -qme close_write --format %w%f ${waitPaths[*]} ) 

    这可能会产生如下内容:

     file: /tmp/test.css, content: Tue Apr 26 18:53:19 CEST 2016 file: /tmp/test.php, content: Tue Apr 26 18:53:21 CEST 2016 file: /tmp/test.php, content: Tue Apr 26 18:53:23 CEST 2016 file: /tmp/test.css, content: Tue Apr 26 18:53:25 CEST 2016 file: /tmp/test.php, content: Tue Apr 26 18:53:27 CEST 2016 newfile: /tmp/test-420b.php, content: Tue Apr 26 18:53:28 CEST 2016 file: /tmp/test.php, content: Tue Apr 26 18:53:29 CEST 2016 file: /tmp/test.php, content: Tue Apr 26 18:53:30 CEST 2016 file: /tmp/test.php, content: Tue Apr 26 18:53:31 CEST 2016 

一些解释:

  • waitPaths=(/{home,tmp})可以写成waitPaths=(/home /tmp)或者只有一个目录: waitPaths=/var/log
  • if条件搜索匹配*.php*.css文件名
  • (($(stat -c %Y-%X $file)))||echo -n new将比较创建修改时间。
  • inotifywait
    • -q保持quiet (不要打印更多,然后需要)
    • -m用于显示器模式:命令不要termine,而是打印每个匹配的事件。
    • -e close_write仅对指定种类的事件作出反应。
    • -f %w%f输出格式: path/file

其他方式:

有一个更复杂的样本:

  • 监听两种事件(CLOSE_WRITE | CREATE)
  • 在发生CLOSE_WRITE事件时,使用新文件列表来标识哪些文件是新的。

在第二个控制台中, 按Ctrl + C ,或在新的终端,三:

 waitPaths=(/{home,tmp}) declare -A newFiles while read path event file; do if [ "$file" ] && ( [ -z "${file##*.php}" ] || [ -z "${file##*.css}" ] ); then if [ "$event" ] && [ -z "${event//*CREATE*}" ]; then newFiles[$file]=1 else if [ "${newFiles[$file]}" ]; then unset newFiles[$file] echo NewFile: $file, content: sed 's/^/>+ /' $file else echo file: $file, content: sed 's/^/> /' $path/$file fi fi fi done < <(inotifywait -qme close_write -e create ${waitPaths[*]}) 

可能会产生类似于:

 file: test.css, content: > Tue Apr 26 22:16:02 CEST 2016 file: test.php, content: > Tue Apr 26 22:16:03 CEST 2016 NewFile: test-349b.css, content: >+ Tue Apr 26 22:16:05 CEST 2016 file: test.css, content: > Tue Apr 26 22:16:08 CEST 2016 file: test.css, content: > Tue Apr 26 22:16:10 CEST 2016 file: test.css, content: > Tue Apr 26 22:16:13 CEST 2016 

使用bash监视新文件和旧文件中的新行

还有一种解决方法是使用像联合数组这样的bashism

样品:

 wpath=/var/log while : ;do while read -a crtfile ;do if [ "${crtfile:0:1}" = "-" ] && [ "${crtfile[8]##*.}" != "gz" ] && [ "${files[${crtfile[8]}]:-0}" -lt ${crtfile[4]} ] ;then printf "\e[47m## %-14s :- %(%a %d %b %y %T)T ##\e[0m\n" ${crtfile[8]} -1 tail -c +$[1+${files[${crtfile[8]}]:-0}] $wpath/${crtfile[8]} files[${crtfile[8]}]=${crtfile[4]} fi done < <( /bin/ls -l $wpath ) sleep 1 done 

这将在/var/log转储每个文件(文件名不以.gz结尾),并观察修改或新文件,然后转储新行。

演示:

  1. 在第一个终端控制台中,点击:

     ext=(php css other) ( while :; do subname='' ((RANDOM%10)) || printf -v subname -- "-%04x" $RANDOM name=test$subname.${ext[RANDOM%3]} printf "%-16s" $name { date +"%a %d %b %y %T" | tee /dev/fd/5 fortune /usr/share/games/fortunes/bofh-excuses } >> /tmp/$name sleep 1 done ) 5>&1 

    你需要用BOFH找借口图书馆来安装fortune

    如果你真的没有fortune ,你可以用它来代替:

     LANG=C ext=(php css other) ( while :; do subname='' ((RANDOM%10)) || printf -v subname -- "-%04x" $RANDOM name=test$subname.${ext[RANDOM%3]} printf "%-16s" $name { date +"%a %d %b %y %T" | tee /dev/fd/5 for ((1; RANDOM%5; 1)) do printf -v str %$[RANDOM&12]s str=${str// /blah, } echo ${str%, }. done } >> /tmp/$name sleep 1 done ) 5>&1 

    这可能会输出如下内容:

     test.css Thu 28 Apr 16 12:00:02 test.php Thu 28 Apr 16 12:00:03 test.other Thu 28 Apr 16 12:00:04 test.css Thu 28 Apr 16 12:00:05 test.css Thu 28 Apr 16 12:00:06 test.other Thu 28 Apr 16 12:00:07 test.php Thu 28 Apr 16 12:00:08 test.css Thu 28 Apr 16 12:00:09 test.other Thu 28 Apr 16 12:00:10 test.other Thu 28 Apr 16 12:00:11 test.php Thu 28 Apr 16 12:00:12 test.other Thu 28 Apr 16 12:00:13 
  2. 在第二个终端控制台中,点击:

     declare -A files wpath=/tmp while :; do while read -a crtfile; do if [ "${crtfile:0:1}" = "-" ] && [ "${crtfile[8]:0:4}" = "test" ] && ( [ "${crtfile[8]##*.}" = "css" ] || [ "${crtfile[8]##*.}" = "php" ] ) && [ "${files[${crtfile[8]}]:-0}" -lt ${crtfile[4]} ]; then printf "\e[47m## %-14s :- %(%a %d %b %y %T)T ##\e[0m\n" ${crtfile[8]} -1 tail -c +$[1+${files[${crtfile[8]}]:-0}] $wpath/${crtfile[8]} files[${crtfile[8]}]=${crtfile[4]} fi done < <(/bin/ls -l $wpath) sleep 1 done 

这将每秒钟

  1. 用于监视目录中的所有条目

    1. 搜索文件 (第一个字符是- ),
    2. 搜索通过test开始的文件名,
    3. 搜索以cssphp结尾的文件名,
    4. 已打印的尺寸与新文件大小进行比较,
    5. 如果新的尺寸更大,
      • 使用tail -c和打印出新的字节
      • 存储新的已经打印的尺寸
    6. 睡1秒

    这可能会输出如下内容:

     ## test.css :- Thu 28 Apr 16 12:00:09 ## Thu 28 Apr 16 12:00:02 BOFH excuse #216: What office are you in? Oh, that one. Did you know that your building was built over the universities first nuclear research site? And wow, aren't you the lucky one, your office is right over where the core is buried! Thu 28 Apr 16 12:00:05 BOFH excuse #145: Flat tire on station wagon with tapes. ("Never underestimate the bandwidth of a station wagon full of tapes hurling down the highway" Andrew S. Tannenbaum) Thu 28 Apr 16 12:00:06 BOFH excuse #301: appears to be a Slow/Narrow SCSI-0 Interface problem ## test.php :- Thu 28 Apr 16 12:00:09 ## Thu 28 Apr 16 12:00:03 BOFH excuse #36: dynamic software linking table corrupted Thu 28 Apr 16 12:00:08 BOFH excuse #367: Webmasters kidnapped by evil cult. ## test.css :- Thu 28 Apr 16 12:00:10 ## Thu 28 Apr 16 12:00:09 BOFH excuse #25: Decreasing electron flux ## test.php :- Thu 28 Apr 16 12:00:13 ## Thu 28 Apr 16 12:00:12 BOFH excuse #3: electromagnetic radiation from satellite debris 

    注意:如果在两次检查之间某个文件被修改了多次,所有修改都将在下一次检查时打印出来。

虽然不是很好,但下面给出(并重复)当前目录中最新文件的最后50行:

 while true; do tail -n 50 $(ls -Art | tail -n 1); sleep 5; done 

你可以使用cronjob每分钟刷新一次:

 $crontabe -e * * * * * /home/script.sh 

如果您需要在一分钟之内刷新,您可以在脚本中使用命令“sleep”。