如何使用bash脚本检测文件夹中的新文件?我想在文件夹中创建文件后立即对其进行处理。是否可以这样做,还是必须安排cron脚本每分钟左右检查一次新文件?

评论

处理完文件后,是否要从文件夹中删除文件?

目录内容更新后如何运行命令的可能重复项?

实际上,提到的另一个可能重复的问题的答案多样化程度较低,并且在跨平台需求的情况下没有帮助。实际上,对于跨平台,我会投票给fswatch(emcrisostomo.github.io/fswatch),也在以下另一个答案的评论中提到了

#1 楼

您应该考虑使用inotifywait作为示例:

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


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

评论


大! inotifywait正是我想要的。

– ihate注册
2011年11月19日在18:50

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

–卢古斯
2013年3月3日在16:44



@Lugoues,现在当您尝试使用-f时,将得到'--filename'选项不再存在。默认情况下,现在已启用在inotifywait的早期版本中启用的选项。因此,您只需要做inotifywait -m / path -e create |我将尝试编辑此答案。

–布鲁诺·布鲁诺斯基(Bruno Bronosky)
2014年4月17日下午6:27

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

–user100278
15年7月30日在13:22

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

– Tim
18年8月4日在13:38



#2 楼

您可以在脚本中使用watch

watch -n 0.1 ls <your_folder>


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

回退

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

评论


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

–乔贝·露西娜(Joabe Lucena)
19 Mar 22 '19 at 17:58

这很酷。我喜欢

–kodmanyagha
20-2-14在19:47

#3 楼

我只是煮熟了,除了在两次检查之间丢失文件的几率很小之外,没有看到其他任何大问题。

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


如果文件处理不正确花费的时间太长,您不应该错过任何新文件。您也可以为活动设置背景...
并不是防弹的,但是在没有诸如inotify这样的外部工具的情况下,它可以达到某些目的。

评论


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

– Michael Sacchi
2015年12月16日在7:34



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

– Michael Sacchi
2015年12月26日在18:44

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

–法汉
16年6月13日在1:29

如果没有inotify的最佳解决方案。我将添加-type f仅过滤掉文件。否则,该文件夹也将被返回。

– ZenUML.com上的Peng
17年5月31日下午4:46

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

– SDsolar
17年11月20日在0:21

#4 楼

我更喜欢incron,因为它更易于管理。本质上,它是一种利用inotify的服务,您可以设置配置以根据文件更改操作执行操作。

例如:

<directory> <file change mask> <command or action>  options
/var/www/html IN_CREATE /root/scripts/backup.sh


您可以在此处查看完整的示例:
http://www.cyberciti.biz/faq/linux-inotify-examples-to-replicate-directories/

评论


Incron从来没有为我工作。基于关于SE的问题,似乎很多人都没有解决它的问题。

–鲍勃
19年11月8日14:38

#5 楼

entr
使用entr是执行此操作的新方法(它是跨平台的)。请注意,entr不使用轮询,因此与许多替代方法相比,它具有巨大的优势。 kqueue(2)的编写旨在使反馈和自动化测试自然而自然地变得普通。使用
apt-get install entr
dnf install entr
brew install entr
进行新添加的目录
说明的选项(来自文档),




inotify(7)跟踪作为输入和出口提供的常规文件的目录如果添加了新文件。此选项还允许显式指定目录。名称以“。”开头的文件将被忽略。

entr以非交互模式运行。在这种模式下,entr不会尝试从TTY读取或更改其属性。

pledge(2)重新加载持久性子进程。与标准操作模式一样,在处理文件系统或键盘事件之前,不会再次执行终止的实用程序。 -d用于在重新启动实用程序之前将其终止。创建了一个进程组以防止Shell脚本屏蔽信号。 -n等待实用程序退出,以确保已关闭套接字等资源。 TTY的控制权不会转移给子进程。



#6 楼

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

您可以使用以下命令:

ls -1A isempty | wc -l


仅检查文件夹是否仍为空,实际上,如果没有新文件(因此isempty文件夹仍为空),它将返回0。另一方面,它将返回一个大于0的值(实际上是文件夹中当前的文件数)。 />
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年5月26日,0:07

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

– andsens
16年11月28日在23:05

#7 楼

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

[Unit]
Description=Start the script

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


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

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

#8 楼

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

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

来完成您想要的事情” d必须切换到类似perl的系统并使用Linux :: Inotify2(python可能也支持inotify,但我是perl的人)。

#9 楼

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

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


#10 楼

以下是我已测试并纳入需要监视特定目录的项目中的,关于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挂载点中找到的文件或目录;上述项目。

#11 楼

在搜索了这里的答案以及上面评论中提到的其他问题的答案后,我认为我会选择fswatch,因为它具有跨平台支持。
它针对不同的显示器使用不同种类的显示器操作系统,可以自动选择合适的操作系统,或者允许一个操作系统指定要使用的操作系统,甚至可以将自定义平台特定的参数传递给相应的显示器。
当前支持的显示器列表为:


基于Apple OS X的File System Events API的监视器。
基于kqueue的监视器,是FreeBSD 4.1中引入的事件通知接口,并且在大多数* BSD系统上受支持
(包括OS X)。
基于inotify的监视器,它是向应用程序报告文件系统更改的Linux内核子系统。
基于File Events Notification的监视器,它是报告文件事件的Solaris / Illumos内核API。
基于ReadDirectoryChangesW的监视器,该Microsoft Windows API报告更改
定期监视文件系统,将文件修改时间保存在内存中并手动计算文件系统更改的监视器,该更改可在状态(2)为任何状态的任何操作系统上运行。
可以使用。


在Debian / Ubuntu Linuxes上似乎可以通过apt-get获得。查看如何通过apt-get安装和使用fswatch。
其作者为fswatch提供了基于FreeBSD和OS-X软件包的安装支持。
还可以在其他OS上进行构建和安装,发现文章和视频,展示了如何在CentOS上制作和安装fswatch。
还有另一篇文章,展示了用于Linux的fswatch的构建/安装(和使用)相同的手动过程。
基于Windows的软件包-基于的安装支持似乎尚不可用(例如,尚无Chocolatey软件包,也没有Vcpkg软件包)
也有大量有关fswatch的文档,尽管最新1.5版的文档目前指向1.4版。
请参阅如何将fswatch 0.x的命令转换为fswatch1.x。
有关手动选择监视器的提示(当前未更新以提及所有监视器)
在此处,此处和此处以及教程中了解有关fswatch用法的信息。在这里介绍
一个名为libfswatch的库与fswatch工具保持同步。请参阅此处,以及此处的更新文档。
请注意,该库的版本与fswatch实用程序本身的版本不同。具体而言,1.14.0库doc状态:

“ libtool的版本控制方案由三个整数描述:
current:revision:age。

current是最重要的该库实现的最近接口号。
修订版是当前接口的实现号。
age是该库实现的最新接口和最旧接口的区别。


请注意,还有另一个类似的软件,称为fswatch(我认为它与go相关)。

评论


对于Solaris,请注意以下注释:“行为取决于监视器。SolarisFile Events Notification将通知您创建文件后目录已更改,但不会提供更多详细信息。这取决于接收方进行扫描。目录内容,并查看已创建的文件。”在github.com/emcrisostomo/fswatch/issues/228

–乔治·比尔比利斯(George Birbilis)
20年8月15日在18:20

另外,请注意许可为GPL v3.0,因此,如果您不想被迫共享源代码,则应避免静态链接至libfswatch(而是动态链接至其共享库),或者更喜欢使用fswatch实用程序您的应用程序关于必须共享fswatch的源代码,猜测共享一个URL到其源代码存储库就足够了(无论如何,该URL具有最新的代码版本)。

–乔治·比尔比利斯(George Birbilis)
20 Aug 15 '18:23



#12 楼

另请参阅Watchman(基于inotify),尤其是在涉及复杂的监视和动作触发时。它不仅适用于Linux,而且适用于Windows和Mac。在A:Watchman上了解更多信息。问:如何监视完整的目录树中Linux的更改?。