【问题标题】:Waiting for a file to be created in Bash等待在 Bash 中创建文件
【发布时间】:2017-02-24 03:49:53
【问题描述】:

我需要创建一个 bash 脚本来等待一个文件被创建。该脚本将在 while 循环中使用 sleep 命令,每 10 秒定期检查一次文件。等待时打印出一条消息。创建文件后显示文件的内容。以下是我试图实现的,它显然不起作用。在这一点上,我不完全确定如何继续。

#!/bin/bash
let file=$1

while '( -f !  /tmp/$1)'
do
       sleep 10
       echo "still waiting"
done

echo "Content of the file $1:"

【问题讨论】:

  • '(...)' 是一个字符串,归结为while true。试试while [ !-f /tmp/$1 ] 或类似的。
  • @MarcB,嗯?根本不是while true;它是while false,因为该字符串不是有效的命令。如果它在测试中,那么它可能是真的。
  • 顺便说一句,在未来,考虑使用bash -x yourscript 来确定执行过程中发生了什么——在这种情况下,这表明我们直接从'( -f ! /tmp/$1)'echo "Content of the file $1:" ,从而排除了 sleep 的问题(因为它根本没有运行)。
  • @MarcB, ...顺便说一句,它应该是 while [ ! -f /tmp/"$1" ] -- !- 之间的空格是强制性的,同样的扩展名周围的引号(以避免宽字符串拆分和全局扩展的一系列不良行为)。或while ! test -f "/tmp/$1",或任何其他写法。

标签: bash unix


【解决方案1】:

这里的问题在于测试,而不是睡眠(正如原始问题所假设的那样)。可能的最小修复可能如下所示:

while ! test -f "/tmp/$1"; do
  sleep 10
  echo "Still waiting"
done

记住while 循环的语法:

while: while COMMANDS; do COMMANDS; done
    Expand and execute COMMANDS as long as the final command in the
    `while' COMMANDS has an exit status of zero.

也就是说,给while的第一个参数,展开循环,是一个命令;它需要遵循与任何其他 shell 命令相同的语法规则。

-f 作为test 的参数是有效的——该命令也可以在名称[ 下访问,在该名称中使用时需要] 作为最后一个参数——但它无效作为一个命令本身——并且当作为字符串的一部分传递时,它甚至不是一个外壳词,可以被解析为一个单独的命令名称或参数。

当您将'( -f ! /tmp/$1)' 作为命令运行时,在引号内,shell 正在寻找具有该名称(包括空格)的实际命令。您的 PATH 中可能没有名为 '/usr/bin/( -f ! /tmp/$1)' 的文件或找到该名称的任何其他命令,因此它总是会失败 - 立即退出 while 循环。


顺便说一句——如果你愿意让你的代码特定于操作系统,除了使用sleep 来等待文件存在之外,还有其他方法。例如,考虑inotifywait,来自inotify-tools 包:

while ! test -f "/tmp/$1"; do
  echo "waiting for a change to the contents of /tmp" >&2
  inotifywait --timeout 10 --event create /tmp >/dev/null || {
    (( $? == 2 )) && continue  ## inotify exit status 2 means timeout expired
    echo "unable to sleep with inotifywait; doing unconditional 10-second loop" >&2
    sleep 10
  }
done

基于 inotify 的接口的好处是它会在文件系统更改后立即返回,并且不会产生轮询开销(如果它阻止系统休眠,这可能尤其重要)。


顺便说一下练习笔记:

  • 在文件名中引用扩展名(即"/tmp/$1")可防止将带有空格或通配符的名称扩展为多个不同的参数。
  • echo 上使用 >&2 命令来记录人类消费,使 stderr 可用于编程消费
  • let 用于数学,而不是通用作业。如果你想使用"$file",这没有错——但赋值应该只是file=$1,前面没有let

【讨论】:

  • Mac 用户可以使用fswatch 代替inotifywaitfswatch --event Created --event Updated "$INPUT_DIR"
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-18
  • 1970-01-01
  • 2015-07-03
  • 2018-05-05
相关资源
最近更新 更多