Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用bash监视目录中预先存在的文件和新文件_Bash_Unix_Inotify_Inotifywait - Fatal编程技术网

使用bash监视目录中预先存在的文件和新文件

使用bash监视目录中预先存在的文件和新文件,bash,unix,inotify,inotifywait,Bash,Unix,Inotify,Inotifywait,我有一个使用inotify工具的脚本 当新文件到达文件夹时,此脚本会发出通知。它对文件执行一些操作,完成后将文件移动到另一个文件夹。(这条线看起来有点像): 使用inotifywait,只能监视新文件。使用路径中的旧文件而不是inotifywait的类似过程将适用于现有文件: for OLDFILE in ${path} do work on/with OLDFILE move NEWFILE no a new directory done 我试着把这两个循环结合起来。首先运

我有一个使用inotify工具的脚本
当新文件到达文件夹时,此脚本会发出通知。它对文件执行一些操作,完成后将文件移动到另一个文件夹。(这条线看起来有点像):

使用
inotifywait
,只能监视新文件。使用路径中的旧文件
而不是
inotifywait
的类似过程将适用于现有文件:

for OLDFILE in ${path} 
do 
   work on/with OLDFILE 
   move NEWFILE no a new directory
done
我试着把这两个循环结合起来。首先运行第二个循环。但是,如果文件到达的速度很快且数量很大,则在第二个循环运行时,文件将到达。这两个循环都不会捕获这些文件

考虑到文件夹中已经存在文件,并且新文件将很快到达文件夹中,如何确保脚本将捕获所有文件

通过使用inotifywait,只能监视新文件

我想问一下“新文件”的定义。指定事件列表,其中还列出了事件,如
create
delete
delete_self
,inotifywait还可以查看“旧文件”(定义为在inotifywait执行之前存在的文件)和目录。您只指定了一个事件
-e modify
,该事件通知${path}内文件的修改,它包括对先前存在的文件和在执行后创建的文件的修改

。。。如何确保脚本将捕获所有文件

您的脚本足以捕获路径中发生的所有事件。如果无法在生成文件的部件和接收文件的部件之间进行同步,则无法执行任何操作,并且始终存在争用条件。如果脚本接收到0%的CPU时间,而生成文件的部分将获得100%的CPU时间,该怎么办?不保证进程之间的cpu时间(除非使用经认证的实时系统…)。实现它们之间的同步

你可以看其他的节目。如果生成站点在准备好文件时关闭文件,请注意关闭事件。此外,您还可以在后台并行运行
workon/with NEWFILE
,以加快执行和读取新文件。但是,如果接收端比发送端慢,如果脚本处理新文件的速度比生成新文件的速度慢,那么您将无能为力

如果文件名中没有特殊字符和空格,我会选择:

inotifywait -m -e modify "${path}" |
while IFS=' ' read -r path event file ;do
    lock "${path}" 
    work on "${path}/${file}"
    ex. mv "${path}/${file}" ${new_location}
    unlock "${path}"
done
其中
lock
unlock
是在脚本和生成部分之间实现的一些锁定机制。您可以在文件创建过程和文件处理过程之间创建通信

我认为您可以使用一些事务文件系统,这将允许您从其他脚本“锁定”一个目录,直到您准备好处理它,但我在该领域没有经验

我试着把这两个循环结合起来。但是,如果文件到达的速度很快且数量很大,则在第二个循环运行时,文件将到达

在运行进程\u旧文件\u循环之前,在后台运行进程\u新文件\u循环。另外,在继续处理现有文件循环之前,最好确保(即同步)inotifywait已成功启动,以便它们之间也没有竞争条件

也许一个简单的例子和/或起点是:

work() {
    local file="$1"
    some work "$file"
    mv "$file" "$predefiend_path"
}

process_new_files_loop() {
    # let's work on modified files in parallel, so that it is faster

    trap 'wait' INT
    inotifywait -m -e modify "${path}" |
    while IFS=' ' read -r path event file ;do
        work "${path}/${file}" &
    done
}

process_old_files_loop() {
    # maybe we should parse in parallel here too?
    # maybe export -f work; find "${path} -type f | xargs -P0 -n1 -- bash -c 'work $1' -- ?

    find "${path}" -type f |
    while IFS= read -r file; do
        work "${file}"
    done
}

process_new_files_loop &
child=$!

sleep 1

if ! ps -p "$child" >/dev/null 2>&1; then
    echo "ERROR running processing-new-file-loop" >&2
    exit 1
fi
process_old_files_loop
wait # wait for process_new_file_loop

如果您真的关心执行速度,并且希望更快地执行,那么可以改用python或C(或除shell以外的任何语言)。Bash不是很快,它是一个shell,应该用来连接两个进程(将一个进程的stdout传递给另一个进程的stdin)并逐行解析流
,而IFS=read-r line
在Bash中速度非常慢,通常应该作为最后的手段使用。也许使用
xargs
xargs-P0-n1 sh-c“在$1;mv$1$path上工作”-
并行
可以加快速度,但一个普通的python或c程序可能要快n倍。

一旦
inotifywait
启动并等待,它会将消息
打印到标准错误。因此,在这一点之后,您需要检查现有文件

因此,一种方法是编写处理标准错误的代码,当它看到该消息时,列出所有现有文件。为了方便起见,您可以将该功能包装到函数中:

function list-existing-and-follow-modify() {
  local path="$1"
  inotifywait --monitor \
              --event modify \
              --format %f \
              -- \
              "$path" \
    2> >( while IFS= read -r line ; do
            printf '%s\n' "$line" >&2
            if [[ "$line" = 'Watches established.' ]] ; then
              for file in "$path"/* ; do
                if [[ -e "$file" ]] ; then
                  basename "$file"
                fi
              done
              break
            fi
          done
          cat >&2
        )
}
然后写:

list-existing-and-follow-modify "$path" \
| while IFS= read -r file
    # ... work on/with "$file"
    # move "$file" to a new directory
  done
注:

  • 如果您不熟悉我使用的
    >(…)
    符号,则称之为“流程替换”;有关详细信息,请参阅
  • 现在,上面的竞态条件与原始竞态条件相反:如果在
    inotifywait
    启动后不久创建了一个文件,则
    列出现有文件并跟随modify
    可能会列出它两次。但是,您可以在
    中轻松地处理该问题,而
    -loop可以使用
    if[[-e“$file”]]
    在对文件进行操作之前确保该文件仍然存在
  • 我有点怀疑你的
    inotifywait
    选项是否真的是你想要的<代码>修改
,尤其是,似乎是错误的事件。但我相信你可以根据需要调整它们。我在上面所做的唯一更改,除了为了清晰/明确而切换到长选项和为了稳健性而添加
--
之外,就是添加
--格式%f
,以便获得文件名,而不需要额外的细节
  • 似乎没有任何方法可以告诉inotifywait
  • 使用除换行符以外的分隔符,所以,我就这样做了。确保避免使用包含换行符的文件名
    在运行inotifyywait脚本之前,只需将“旧”文件移出即可?@redCricket我想我就是这么做的。问题是文件到达得太快,所以考虑到我已经有了X a
    list-existing-and-follow-modify "$path" \
    | while IFS= read -r file
        # ... work on/with "$file"
        # move "$file" to a new directory
      done