等待在 Bash 中创建文件 [英] Waiting for a file to be created in Bash

查看:36
本文介绍了等待在 Bash 中创建文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要创建一个 bash 脚本来等待创建文件.该脚本将在 while 循环中使用 sleep 命令每隔 10 秒定期检查文件.等待时打印一条消息.创建文件后显示文件的内容.以下是我尝试实施的内容,但显然行不通.在这一点上,我不完全确定如何进行.

#!/bin/bash让文件=$1而 '( -f !/tmp/$1)'做睡 10echo "还在等待"完毕echo "文件 $1 的内容:"

解决方案

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

while !测试 -f "/tmp/$1";做睡 10echo "还在等待"完毕

<小时>

记住 while 循环的语法:

<块引用>

while:while 命令;执行命令;完毕展开并执行 COMMANDS 只要最后一个命令在`while' 命令的退出状态为零.

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

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

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

<小时>

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

while !测试 -f "/tmp/$1";做echo "正在等待更改/tmp 的内容" >&2inotifywait --timeout 10 --event create/tmp >/dev/null ||{(( $? == 2 )) &&continue ## inotify exit status 2 表示超时已过期回声无法与 inotifywait 一起睡觉;进行无条件的 10 秒循环">&2睡 10}完毕

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

<小时>

顺便说一下,一些练习笔记:

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

I need to create a bash script to wait for a file to be created. The script will use sleep command inside a while loop to periodically check on a file every 10 seconds. Print out a message while waiting. Display the content of the file once the file is created. Below is what I have tried to implement and it obviously does not work. At this point, I'm not entirely sure how to proceed.

#!/bin/bash
let file=$1

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

echo "Content of the file $1:"

解决方案

The problem here is with the test, not the sleep (as the original question hypothesized). The smallest possible fix might look as follows:

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


Keep in mind the syntax for a while loop:

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.

That is to say, the first argument given to while, expanding the loop, is a command; it needs to follow the same syntax rules as any other shell command.

-f is valid as an argument to test -- a command which is also accessible under the name [, requiring a ] as the last argument when used in that name -- but it's not valid as a command in and of itself -- and when passed as part of a string, it's not even a shell word that could be parsed as an individual command name or argument.

When you run '( -f ! /tmp/$1)' as a command, inside quotes, the shell is looking for an actual command with exactly that name (including spaces). You probably don't have a file named '/usr/bin/( -f ! /tmp/$1)' in your PATH or any other command by that name found, so it'll always fail -- exiting the while loop immediately.


By the way -- if you're willing to make your code OS-specific, there are approaches other than using sleep to wait for a file to exist. Consider, for instance, inotifywait, from the inotify-tools package:

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

The benefit of an inotify-based interface is that it returns immediately upon a filesystem change, and doesn't incur polling overhead (which can be particularly significant if it prevents a system from sleeping).


By the way, some practice notes:

  • Quoting expansions in filenames (ie. "/tmp/$1") prevents names with spaces or wildcards from being expanded into multiple distinct arguments.
  • Using >&2 on echo commands meant to log for human consumption keeps stderr available for programmatic consumption
  • let is used for math, not general-purpose assignments. If you want to use "$file", nothing wrong with that -- but the assignment should just be file=$1, with no preceding let.

这篇关于等待在 Bash 中创建文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆