监视文件夹中是否有新文件的脚本?


Answers:


151

您应该考虑使用inotifywait,例如:

inotifywait -m /path -e create -e moved_to |
    while read path action file; do
        echo "The file '$file' appeared in directory '$path' via '$action'"
        # do something with the file
    done

在Ubuntu中inotifywait是由inotify-tools软件包提供的。从3.13版本开始(Ubuntu 12.04中当前使用)inotifywait将包含不带-f选项的文件名。较旧的版本可能需要强制执行。需要注意的重要一点是,-eto选项inotifywait是进行事件过滤的最佳方法。同样,您的read命令可以将位置输出分配给多个变量,您可以选择使用或忽略这些变量。无需使用grep / sed / awk预处理输出。


1
大!这inotifywait正是我想要的。
ihateto11年

2
只想更新这个。您不需要awk即可实现。您可以使用'-e create'过滤事件,并通过执行'-f%f'来获取文件名,或者使用'-f%w%f'来获取完整路径。因此,上述脚本的第一行变为:inotifywait -m / path -f%w%f -e create |
Lugoues

2
@Lugoues,现在当您尝试使用-f时,您将得到The '--filename' option no longer exists. The option it enabled in earlier versions of inotifywait is now turned on by default.So,那么您只需要做的inotifywait -m /path -e create |就是尝试编辑此答案。
布鲁诺·布鲁诺斯基

1
现在还有一个名为的便携式工具fswatch。我没有写它,但是它是开源的,我使用它。

1
@Wender inotfiywait触发时在一行上输出3条信息。内置的“ read” bash读取输入行,并将三个信息的每一个分配给一个变量。因此,第一部分分配给变量路径,第二部分分配给动作,第三部分分配给文件。为这些变量分配值之后,它们便可以在以后使用(例如在回声线上)。更多信息:tldp.org/LDP/Bash-Beginners-Guide/html/sect_08_02.html
Tim


24

我刚做完这个,并没有看到任何大的问题,除了两次检查之间丢失文件的几率很小。

while true
do
       touch  ./lastwatch
       sleep 10
       find /YOUR/WATCH/PATH -cnewer ./lastwatch -exec SOMECOMMAND {} \;
done

如果您的文件处理时间不太长,则不应错过任何新文件。您还可以为活动设置背景……这不是防弹的,但是在没有inotify之类的外部工具的情况下,它可以达到某些目的。


接得好。我做了一些改进,以支持文件名中的空格。
Michael Sacchi 2015年

绝对。那是要走的路。不太确定为什么要走这条路,我通常使用-exec。
Michael Sacchi 2015年

它不是实时的。实时永远是最好的
-Farhan

3
如果inotify没有可用的最佳解决方案。我-type f只添加过滤出文件。否则,该文件夹也将被返回。
小鹏-ZenUML.com

-f filename是的- 选项很棒。因此,剩下的唯一问题是如何使它在重新启动时启动。我将在我的太阳能发电厂中使用它,os.system("ssh me@mysystem ' ( touch /home/me/alarms/low24 ) '")因此创建此文件将使主计算机使用espeak并宣布低电压。它已经给我发送了一封电子邮件,但是由于我的系统已经在最忙的时候说了时间,所以剩下的时间都包含了。 askubuntu.com/questions/977613/...
SDsolar

17

您可以watch在脚本中使用

watch -n 0.1 ls <your_folder>

监视您的文件夹并每隔0.1秒列出其中的所有内容

退税

不是实时的,因此,如果在不到0.1秒的时间内创建和删除文件,则此操作将无效,watch仅支持最少0.1秒。


那正是我想要记住的!非常感谢!!
Joabe Lucena

9

我假设目标文件夹(isempty为方便起见,我将其称为)是空的,并且您正在等待将一个或多个文件放到那里。

您可以使用以下命令:

ls -1A isempty | wc -l

只是检查文件夹是否仍然为空,实际上,如果没有新文件(因此isempty文件夹仍然为空),它将返回0;或者,另一方面,它将返回大于0的值(实际上是数字)文件夹中当前文件的数量)。

那就是说愚蠢的if / then测试可以完成其余的工作:

if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi

当然,该do_something功能将必须处理文件isempty夹中的文件,然后在处理后将其从文件夹本身中删除。

在crontab中添加如下所示的一行将每分钟运行一次检查,并且do_something如果该文件夹当然不为空,则将触发操作:

* * * * *     if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi

该解决方案适用于挂载的远程文件系统。inotify-tools开发人员正在从事保险丝工作(或于2014年中期完成)。
Rondo 2015年

3
您不应该使用ls脚本。请改用find或使用简单的通配:mywiki.wooledge.org/ParsingLs
andsens

6

如果要检测新文件,请对其进行处理,最后删除继续处理的文件,可以使用systemd.path。此方法基于inotify。有一个DirectoryNotEmpty选项,因此systemd可以在检测到目录中的任何文件时始终运行脚本。您必须记住,仅当您可以删除已处理的文件并且脚本将目录留为空白时,它才有效。

首先准备mymonitor.service文件

[Unit]
Description=Start the script

[Service]
Type=oneshot
ExecStart=/path/to/your/script

接下来转到mymonitor.path定义路径

[Unit]
Description= Triggers the service

[Path]
DirectoryNotEmpty=/path/to/monitor

[Install]
WantedBy=multi-user.target

如果.path文件的名称与服务的名称相同,则无需在.path文件中指定服务名称。

它基于监视虚拟文件的访问


4

entr

使用entr是执行此操作的新方法(它是跨平台的)。注意entr不使用轮询,因此与许多替代方法相比,它具有巨大的优势。

用于kqueue(2)inotify(7)避免轮询。entr编写该软件是为了使快速的反馈和自动化的测试自然而自然地完成。

在BSD上,它使用 pledge(2)

您可以使用安装

apt-get install entr
dnf install entr

您可以使用以下方式跟踪目录以查找新添加的内容

while $(true); do
  # echo ./my_watch_dir | entr -dnr echo "Running trigger..."
  echo ./my_watch_dir | entr -dnr ##MY COMMAND##
done;

选项说明(来自文档),

  • -d 跟踪作为输入提供的常规文件目录,如果添加新文件,则退出。此选项还允许显式指定目录。名称以“。”开头的文件。被忽略。
  • -n在非交互模式下运行。在此模式下,entr不会尝试从TTY读取或更改其属性。
  • -r 重新加载一个持久的子进程。与标准操作模式一样,在处理文件系统或键盘事件之前,不会再次执行终止的实用程序。 SIGTERM用于在重新启动实用程序之前将其终止。创建了一个进程组以防止Shell脚本屏蔽信号。 entr等待实用程序退出以确保已关闭套接字等资源。TTY的控制权不会转移到子进程中。

2

Bash无法轻松做到这一点。您必须基本上获得该文件夹中所有文件的列表,并定期获取一个新列表并进行比较,以查看发生了什么变化。

您正在寻找的称为inotify。它内置在linux内核中,您基本上可以坐在那里等待事情发生,这时inotify会返回并说“嘿,有一个名为foobar的新文件”

要实现您想要的功能,您必须切换到类似perl的设备并使用Linux :: Inotify2(python可能也支持inotify,但我是perl人士)。


0

这适用于cygwin和Linux。某些以前的写入文件的解决方案将导致磁盘损坏。这个密码没有这个问题:

SIG=1
SIG0=$SIG
while [ $SIG != 0 ] ; do
 while [ $SIG = $SIG0 ] ; do
   SIG=`ls -1 | md5sum | cut -c1-32`
   sleep 10
 done
 SIG0=$SIG
 ls -lrt | tail -n 1
done

0

以下是我测试过的Stackoverflow示例的精简版本,并将其合并到需要监视特定目录的项目中。

Var_dir="${1:-/tmp}"
Var_diff_sleep="${2:-120}"
Var_diff_opts="--suppress-common-lines"
Func_parse_diff(){
    _added="$(grep -E '>' <<<"${@}")"
    if [ "${#_added}" != "0" ]; then
        mapfile -t _added_list <<<"${_added//> /}"
        _let _index=0
        until [ "${#_added_list[@]}" = "${_index}" ]; do
            _path_to_check="${Var_dir}/${_added_list[${_index}]}"
            if [ -f "${_path_to_check}" ]; then
                echo "# File: ${_path_to_check}"
            elif [ -d "${_path_to_check}" ]; then
                echo "# Directory: ${_path_to_check}"
            if [ -p "${_path_to_check}" ]; then
                echo "# Pipe: ${_path_to_check}"
            fi
            let _index++
        done
        unset _index
    fi
}
Func_watch_bulk_dir(){
    _current_listing=""
    while [ -d "${Var_dir}" ]; do
        _new_listing="$(ls "${Var_dir}")"
        _diff_listing="$(diff ${Var_dec_diff_opts} <(${Var_echo} "${_current_listing}") <(${Var_echo} "${_new_listing}"))"
        if [ "${_diff_listing}" != "0" ]; then
            Func_parse_diff "${_diff_listing}"
        fi
        _current_listing="${_new_listing}"
        sleep ${Var_diff_sleep}
    done
}

这是指向脚本的链接,该脚本使用上述版本的修改版来自动解密在其sshfs挂载点中找到的文件或目录;上述项目。

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.