【问题标题】:Shell: Wait that a file has been copiedShell:等待文件已被复制
【发布时间】:2012-05-07 12:59:39
【问题描述】:

我有一个 shell 脚本,它列出文件夹的文件,然后对它们执行操作(打印成 PDF),但我经常得到一个空白 PDF。如果我删除生成的 PDF,新的 PDF 始终会正确生成。

我的印象是因为我的脚本在文件被完全复制之前开始打印(副本是通过操作系统资源管理器制作的,保存为,或者只是复制粘贴)。

当有人添加新文件时,绝对不是我来管理,副本来自使用网络共享的用户。

那么有没有办法拥有这样的东西?

for inputFile in `ls -l $SearchPattern | grep ^- | awk '{print $9}'`
do
   //CHECK_THAT_THE_FILE_HAS_ALREADY_BEEN_FULLY_SAVED_ONCE 
   //DO_MY_PRINT_HERE
done

【问题讨论】:

  • for inputFile in $SearchPattern; do ... 有什么问题?
  • 您能否设置一个 crontab 以每小时(或?)运行一次,并且只处理时间戳超过 5(或?)分钟的文件?祝你好运。
  • @glennjackman 正则表达式不是全局字符。大多数正则表达式不可能写成 glob 模式。 grep '^-' 在ls -l 输出中说“给我所有普通文件”。
  • @Jens,我会质疑“大多数正则表达式不可能写成 glob 模式”,确实很复杂,但是正则表达式 ^- 是 glob -*。无论如何,for inputFile in $SearchPattern; do [[ ! -f "$inputFile" ]] && continue; ...

标签: bash shell unix sh


【解决方案1】:

如果您在 Linux 下运行并且文件系统对于您的服务器是本地,那么您可以使用inotify 子系统等待文件关闭然后触发操作。 inotify-tools 包包括 inotifywait 程序,它向 shell 脚本公开了 inotify 功能。

例如,您可以在这样的目录中监视close_write 事件:

inotifywait -e close_write -m /path/to/directory

运行此命令,执行以下操作:

echo hello > /path/to/directory/file

将生成如下输出:

/path/to/directory/ CLOSE_WRITE,CLOSE hello

所以你有生成事件的目录和文件名。在 shell 脚本中,您可以将其导入循环:

inotifywait -e close_write -m /path/to/directory | while read dir flags file; do
  ...do something with the file...
done

【讨论】:

  • 我在这台服务器上没有 inotify 助手
【解决方案2】:

正如有人指出的那样,使用文件修改时间可能很有用。我很快就完成了这个可能有用的脚本。它将一直等到自给定文件的最后修改时间以来经过 5 秒:

#!/bin/bash

function getTimeFromLastChange() {
    file=${1}
    let lastAccess=$(stat --format=%Y ${file})
    let now=$(date +%s)
    let timePassed=$((now - lastAccess))
    echo ${timePassed}
}

file=./test
while [ true ]; do
    let lastChange=$(getTimeFromLastChange ${file})
    if [ "${lastChange}" -lt 5 ]; then
        echo "waiting"
        sleep 1
    else
        echo "done"
        exit
    fi
done

echo ${timePassed}

这里的关键是“getTimeFromLastChange”函数,它使用 stat (http://linux.die.net/man/1/stat) 来获取自 unix 纪元时间以来给定文件的最后修改时间(以秒为单位)。然后,它将使用日期 (http://linux.die.net/man/1/date) 获取当前时间(同样,自 unix 纪元时间以来的秒数),减去它们,并计算自以来的总秒数最后修改时间。

主循环将一直等待,直到经过一些“安全”的秒数。因此,您可以尝试调整此参数并打印数秒前写入/修改的文件。

示例运行:

marcelog@host ~ $ touch ./test
marcelog@host ~ $ ./try.sh
waiting
waiting
waiting
done

这不是 100% 安全的。但我认为值得一试。

希望对你有帮助!

【讨论】:

  • 修改时间是什么时候?在副本的开头还是结尾?
  • 复制大文件时,您应该注意到修改时间随着数据写入磁盘而更新。所以它实际上是通过整个复制过程更新的。我刚刚通过复制一个大文件(超过 600M)尝试了我发布的脚本,它将按预期等待,直到自上次修改时间过去 5 秒(这应该是复制/添加到文件中的最后一个数据,实际上是复制过程结束)
【解决方案3】:

您应该检查数据的修改时间并对此设置阈值。 没有其他(简单的)方法可以查看文件是否没有更多待处理的操作。

所以你应该使用

ls -l -t

在您找到上面的语句并根据您的时间阈值通过“排序”将其管道化。

问候

【讨论】:

    【解决方案4】:

    我以使用结束

    for inputFile in `find $SearchPattern2 -maxdepth 1 -type f -cmin +1 -iname "*.pdf"`
    

    -cmin +1 表示查找,即只列出修改时间>1分钟前的文件。

    它不是 100% 安全的,但它可以处理我所有的情况,并且有很大的余地。

    我没有在几秒钟内找到如何做到这一点

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-23
      • 1970-01-01
      • 2016-03-20
      • 2010-11-27
      • 2013-06-21
      • 2012-05-30
      相关资源
      最近更新 更多