等待在 Bash 中创建文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40047801/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 15:19:05  来源:igfitidea点击:

Waiting for a file to be created in Bash

bashunix

提问by J.Clark

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.

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

#!/bin/bash
let file=

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

echo "Content of the file :"

回答by Charles Duffy

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/"; do
  sleep 10
  echo "Still waiting"
done


Keep in mind the syntax for a whileloop:

请记住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: 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.

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

-fis 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 couldbe parsed as an individual command name or argument.

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

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 whileloop immediately.

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



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

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

while ! test -f "/tmp/"; 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).

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



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 >&2on echocommands meant to log for human consumption keeps stderr available for programmatic consumption
  • letis 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.
  • 在文件名中引用扩展(即"/tmp/$1")可防止带有空格或通配符的名称被扩展为多个不同的参数。
  • 使用>&2echo意味着日志供人食用的命令保持标准错误可以编程消费
  • let用于数学,而不是通用任务。如果你想使用"$file",那没有错——但赋值应该是file=$1,没有前面的let