在监视文件夹中新文件的小脚本中,该脚本似乎正在查找错误的文件

Posted

技术标签:

【中文标题】在监视文件夹中新文件的小脚本中,该脚本似乎正在查找错误的文件【英文标题】:In a small script to monitor a folder for new files, the script seems to be finding the wrong files 【发布时间】:2011-11-16 22:12:34 【问题描述】:

我正在使用此脚本来监视下载文件夹中是否有正在创建的新 .bin 文件。但是,它似乎不起作用。如果我删除 grep,我可以让它复制在 Downloads 文件夹中创建的任何文件,但是使用 grep 它不起作用。我怀疑问题在于我如何尝试比较这两个值,但我真的不确定该怎么做。

#!/bin/sh

downloadDir="$HOME/Downloads/"
mbedDir="/media/mbed"

inotifywait -m --format %f -e create $downloadDir -q | \
while read line; do
    if [ $(ls $downloadDir -a1 | grep '[^.].*bin' | head -1) == $line ]; then
        cp "$downloadDir/$line" "$mbedDir/$line"
    fi
done

【问题讨论】:

我不清楚它应该做什么。比较的目的是什么?如所写,它似乎只复制第一个(按字母顺序)包含“bin”的文件(不一定以“bin”结尾,因为 grep 模式未锚定到行尾)。 2.事情,1. 总是用 db-quotes 包围未知性质的变量,即"$line" 如果你在$line 的值中出现一个可能破坏事物的空格,2. 打开 shell 调试,即set -vx在你的 while 循环之上。然后您将看到每一行/代码块以及分配给每个变量的值。然后很容易看出这些失败的地方。如果您无法弄清楚,请编辑您的帖子以包含相关的调试输出。祝你好运。 @GordonDavisson 比较的目的是只移动与某个正则表达式匹配的文件,尽管我确实忘记锚定所说的正则表达式。我看不出如何让 inotify 只移动与模式匹配的东西。 【参考方案1】:

ls $downloadDir -a1 | grep '[^.].*bin' | head -1 是错误的处理方式。要了解原因,假设您在下载目录中有名为 a.txtb.bin 的文件,然后添加了 c.bininotifywait 将打印 c.binls 将打印 a.txt\nb.bin\nc.bin(带有实际换行符,而不是 \n),grep 会将其细化为 b.bin\nc.binhead 将删除除第一行之外的所有内容 @ 987654332@,与 c.bin 不匹配。您需要检查$line 以查看它是否以.bin 结尾,而不是扫描目录列表。我会给你三种方法来做到这一点:

第一个选项,使用 grep 检查$line,而不是列表:

if echo "$line" | grep -q '[.]bin$'; then

请注意,我使用-q 选项来抑制 grep 的输出,而只是让 if 命令检查其退出状态(如果找到匹配则成功,否则失败)。此外,RE 锚定到行尾,句点在括号中,因此它只会匹配实际的句点(通常,正则表达式中的 . 匹配任何单个字符)。 \.bin$ 也可以在这里工作。

第二个选项,利用shell的能力编辑变量内容,看看$line是否以.bin结尾:

if [ "$line%.bin" != "$line" ]; then

"$line%.bin" 部分给出了 $line 的值,.bin 如果存在,则从末尾修剪。如果这与$line 本身不同,那么$line 必须以.bin 结尾。

第三种选择,直接使用bash的[[ ]]表达式进行模式匹配:

if [[ "$line" == *.bin ]]; then

这是(恕我直言)最简单和最清晰的一个,但它只适用于 bash(即您必须以 #!/bin/bash 启动脚本)。

其他注意事项:为避免文件名中的空格和反斜杠出现一些可能的问题,请使用while IFS= read -r line; do 并认真遵循@shellter 关于双引号的建议。

另外,我对 inotifywait 不是很熟悉,但是 AIUI 它的-e create 选项会在文件创建时通知您,而不是在其内容完全写出时通知您。根据时间的不同,您可能会复制部分写入的文件。

最后,您无需检查重复的文件名。如果您下载一个名为foo.bin 的文件,它会被复制,然后删除原始文件,然后下载另一个名为foo.bin 的文件,会发生什么情况。就像现在的脚本一样,它会默默地覆盖第一个foo.bin。如果这不是您想要的,您应该添加如下内容:

if [ ! -e "$mbedDir/$line" ]; then
    cp "$downloadDir/$line" "$mbedDir/$line"
elif ! cmp -s "$downloadDir/$line" "$mbedDir/$line"; then
    echo "Eeek, a duplicate filename!" >&2
    # or possibly something more constructive than that...
fi

【讨论】:

以上是关于在监视文件夹中新文件的小脚本中,该脚本似乎正在查找错误的文件的主要内容,如果未能解决你的问题,请参考以下文章

如何在一个脚本中监视javascript函数,该脚本被注入jsdom用于测试目的?

在 macOS Catalina 下的 Finder 中查找活动壁纸文件的脚本

Powershell 查找和移动受密码保护的 PDF 文件

我正在尝试编写python脚本来查找超过1000行的文件中的字符串,并在该字符串匹配后删除几行(10)

在 Perl 脚本中使用 File::Find 时忽略整个目录

在过去 1 分钟创建的文件中查找特定单词的 Powershell 脚本