在 Linux 的目录中添加新文件时如何执行任务

本指南将阐述如何在Linux系统中利用文件系统事件(也称为通知)功能,以便在目录中出现新文件时立即收到通知。 这项技术可作为触发器,用于自动化系统上的各种常规任务。

我们将创建一个脚本,该脚本能够监控特定目录,并对新添加的文件执行操作。 当检测到新文件时,脚本会自动将其压缩并移动到另一个指定目录。 该脚本的核心功能依赖于名为inotify-tools的工具包,它利用了inotify子系统。 首先,我们需要安装此工具包并进行一些初步实验。

安装 inotify-tools 和 gzip

对于使用Ubuntu或任何基于Debian的Linux发行版的用户,可以通过apt-get命令在系统中安装必要的软件包。 而其他Linux发行版的用户,则应使用其各自发行版的包管理工具进行安装。

sudo apt-get install inotify-tools gzip

初探 inotify-tools

让我们先从观察一个目录开始,看看当新文件到达时会触发哪些事件。我们将使用inotifywatch工具,它是inotify-tools工具包的一部分。首先,创建一个名为incoming的新目录:

mkdir incoming

通过执行以下命令开始监视这个目录:

inotifywatch -v incoming

此命令指示inotify监控incoming目录内的所有文件系统事件。 -v选项会使该工具打印出额外的详细信息。 由于我们没有指定超时时间(-t选项),命令将持续收集事件,直到我们按下CTRL+C退出。此时,您的终端应该显示类似下面的内容:

现在,打开一个新的终端窗口(或标签页),切换到incoming目录。 使用touch命令创建一个名为newfile的新文件。

cd incoming/
touch newfile

然后,返回到第一个终端窗口,并按下CTRL+C停止inotifywatch

控制台将显示一个事件表格,其中显示了createopenattribclose_write事件的实例。 这四个事件发生在当我们使用touch命令创建一个新文件时,设置文件的访问属性,打开文件写入一个空的终止符,然后关闭文件之后。 这些只是inotify-tools可以在文件系统上监视的众多事件中的一部分。 您可以在inotifywatch的帮助文档中查看完整的事件列表。

在本例中,我们只关注以下两个事件:

create – 当目标目录中创建新文件时。
moved_to – 当文件从其他位置移动到目标目录时。

我们再次尝试使用inotifywatch,但这次只监控这两个事件。在第一个终端窗口中运行此命令:

inotifywatch -v -e create -e moved_to incoming

在第二个终端窗口或标签页中,我们尝试创建一个新文件,修改它的内容,然后将一个文件从其他位置移动到目标目录。所有这些命令都从主目录运行。

touch incoming/created
echo Testing123 >> incoming/created
touch /tmp/created2
mv /tmp/created2 incoming/

返回第一个终端窗口,按下CTRL+C停止inotifywatch。我们将看到如下的输出:

只统计了两个事件:创建名为created的文件,以及将名为created2的现有文件移动进来。其他所有的操作,比如对created的修改,都被忽略了。

监控目录并执行任务

既然我们了解了要跟踪的事件,我们可以使用另一个名为inotifywait的工具,该工具会阻塞执行直到目标目录中创建或移动文件。 我们将使用与inotifywatch相同的参数,并指定我们希望如何格式化文件名以用于我们的任务。

在开始之前,我们需要一个目录来存储已经处理过的文件。创建一个名为processed的目录:

mkdir processed

接下来,创建一个名为watch-incoming.sh的新脚本,并添加以下内容:

#!/bin/bash

TARGET=~/incoming/
PROCESSED=~/processed/

inotifywait -m -e create -e moved_to --format "%f" $TARGET 
        | while read FILENAME
                do
                        echo Detected $FILENAME, moving and zipping
                        mv "$TARGET/$FILENAME" "$PROCESSED/$FILENAME"
                        gzip "$PROCESSED/$FILENAME"
                done

这个脚本使用-m选项来执行inotifywait命令。这使得该命令无限期地监视变更。每当检测到新事件时,文件名会传递给read命令并赋值给FILENAME变量。然后执行while循环下的代码块,首先将文件移动到processed目录,然后对其进行gzip压缩。原始文件会被压缩文件替换,文件名以.gz结尾。

让我们授予这个脚本的执行权限并从我们的主目录运行它。

chmod u+x watch-incoming.sh
./watch-incoming.sh

打开第二个终端窗口,在incoming目录中创建一个新文件。列出incomingprocessed目录的内容,查看检测到的事件结果:

我们复制到incoming目录的原始文本文件被脚本检测到,复制到processed目录,然后使用gzip压缩。

现在,我们可以执行更有趣的任务,因为我们能够监控到达目录的新文件。例如,我们可以为图像文件添加水印,将原始视频压缩为mp4格式,甚至将我们看到的每个新文件上传到Amazon S3存储桶。这个脚本是开始构建您自己的工作流程,并自动化系统上的常用任务的一个很好的起点。