Bash脚本检测目录中文件的更改


10

我正在尝试制作一个脚本,用于检测目录中的任何文件是否在2秒的间隔内被更改。到目前为止,我有:

#!/bin/bash
for FILE in "${PWD}/*"
do
    SUM1="$(md5sum $FILE)"
    sleep 2
    SUM2="$(md5sum $FILE)"
    if [ "$SUM1" = "$SUM2" ];
    then
        echo "Identical"
    else
        echo "Different"
    fi
done

这只输出一次“ Identical”值,我希望它检查每个文件并为每个文件输出“ Identical”或“ Different”。

编辑:可以不安装inotify-tools软件包就完成此操作吗?

Answers:


11

正如其他人所解释的那样,使用inotify是更好的解决方案。我只解释为什么您的脚本失败。首先,无论您使用哪种语言编程,每当尝试调试某些内容时,第一个规则都是“打印所有变量”:

$ ls
file1  file2  file3
$ echo $PWD    
/home/terdon/foo
$ for FILE in "${PWD}/*"; do echo "$FILE"; done
/home/terdon/foo/*

因此,如您在上面看到的,$FILE实际上扩展为$PWD/*。因此,循环仅在字符串 上运行一次/home/terdon/foo/*,而不在目录中的每个文件上单独运行。然后,md5sum命令变为:

md5sum /home/terdon/foo/*

换句话说,它md5sum一次在目标目录中的所有文件上运行,而不是在每个文件上运行。

问题是您引用了glob扩展,这阻止了它的扩展:

$ echo "*"
*
$ echo *
file1 file2 file3

尽管变量应该几乎总是用引号引起来,但不应该使用glob,因为这会使它们成为字符串而不是glob。

您的意思是:

for FILE in "${PWD}"/*; do ...

但是,这里没有理由使用$PWD它,没有添加任何有用的东西。上面的行等效于:

for FILE in *; do

另外,请避免对外壳程序变量使用大写字母。这些用于系统设置的环境变量,最好将自己的变量保留为小写。

考虑到所有这些,这是脚本的一个有效的改进版本:

#!/bin/bash
for file in *
do
    sum1="$(md5sum "$file")"
    sleep 2
    sum2="$(md5sum "$file")"
    if [ "$sum1" = "$sum2" ];
    then
        echo "Identical"
    else
        echo "Different"
    fi
done

虽然for FILE in "${PWD}"/*; do在同一集合上工作,for FILE in *; do但并不完全等效,因为后者不包含路径名。
兰伯特

1
@Lambert是正确的,但在这里没有区别,因为根据定义,脚本将从$ PWD运行
terdon

使用md5sum -- "$file"而不是md5sum "$file"处理文件以开头的情况是一个好主意-。当然您还应该使您的md5sum实现支持--选项定界符结尾。
哈罗德·菲舍尔

9

您绝对可以从命令行使用inotify-tools,例如:

inotifywait -r  -m /dir/to/monitor/

人inotifywait

-m--monitor

无限执行,而不是在收到单个事件后退出。默认行为是在第一个事件发生后退出。

这是一个连续监视的脚本,该脚本是从man文件中复制的inotifywait

#!/bin/sh
while inotifywait -e modify /var/log/messages; do
  if tail -n1 /var/log/messages | grep apache; then
    kdialog --msgbox "Blah blah Apache"
  fi
done

5

您可以使用该inotify-tools程序包实时监视文件夹中的所有更改。例如,它包含该inotifywait工具,您可以像这样使用它:

> inotifywait /tmp
Setting up watches.
Watches established.
/tmp/ MODIFY test

您可以使用标志仅过滤某些事件或某些文件。该inotifywatch工具收集文件系统使用情况统计信息,并输出每个inotify事件的计数。

例如,您可以在此处找到更多示例。

如果要使用其他工具进行监视,则可以将find其与-mmin参数一起使用(修改的分钟数)。由于2秒大约是0.033分钟,因此您可以使用:

find . -type f -mmin 0.033

1

如果要每两秒钟进行一次监视,则可以用以下方法来检查支票:

while true
do
    <your steps>
    sleep 2
done

虽然这将顺序测试文件,并且将为每个找到的文件等待2秒,但我建议将检查转换为功能:

function _check_file()
{
    SUM1=$(md5sum "$@")
    sleep 2
    SUM2=$(md5sum "$@")
    if [ "$SUM1" == "$SUM2" ];
    then
        echo "$@: Identical"
    else
        echo "$@: Different"
    fi
}

可以在while循环中使用:

while true
do
    for FILE in "${PWD}/"*
    do
        if [ -f "$FILE" ]
        then
            _check_file "$FILE" &
        fi
    done
    sleep 2
done

请注意&,在背景中执行与号操作是为了并行执行文件检查。请注意,这可能会影响性能,具体取决于目录中找到的文件数量。

另请注意,我更改了echo行以包含文件名("$@"),以可视化发现哪个文件相同/不同。


0
#!/bin/bash
# pass one or more folders as arguments
while true; do
  for f in "$@"; do
    date
    echo "Checking $f and subfolders"
    find=$(find "$f" -type f)
    while read -r f2; do
      # strip non-alphanumeric from filename for a variable var name
      v=${f2//[^[:alpha:]]/}
      r=$(md5sum "$f2")
      if [ "$r" = "${!v}" ]; then
        echo "Identical $f2"
      else
        echo "Different $f2"
      fi
      eval "${v}=\$r"
    done <<< "$find"
  done
  sleep 2
done
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.