shell脚本检查文件的可用性1小时,一小时后如果文件不存在,它将回显“超时”

shell脚本检查文件的可用性1小时,一小时后如果文件不存在,它将回显“超时”

我写了这段代码。但问题是每 300 秒后,当 $fname 存在从循环中退出时,它会打印“Time over”。如果文件未到达,我希望 1 小时后“超时”,但 300 秒后它开始打印“超时”

echo "enter file name"

read fname

START=`date +%s`
while [ $(( $(date +%s) - 3600 )) -lt $START ]; do
  if [ -e $fname ]
  then
    echo "$fname present"
    break
    sleep 300
  else
    echo "Time Over"
  fi
done

答案1

我认为你已经很接近了,但你的脚本的某些方面看起来过于复杂。

您可以尝试以下while循环:

#!/bin/sh

timeout=3600
granularity=300
elapsed=0

echo "Please enter the filename"
read -r file

while [ "$elapsed" -lt "$timeout" ]
do
    if [ -f "$file" ]
    then
        break
    fi

    sleep "$granularity"
    elapsed=$((elapsed+granularity))
done

# Was the loop broken because the file appeared, or did it time out?
if [ -f "$file" ]
then
    echo "$file has appeared"
else
    echo "Time over"
fi

这将每秒检查一次$granularity文件是否存在,直到$timeout超过该值。如果文件已经出现,脚本将跳出循环。

您的方法的问题是“超时”输出位于else定期检查的分支中,因此会发生每次迭代循环时如果找不到该文件。相反,我建议检查循环之后如果您的测试变量(在脚本中的输出date)超出了边界(表示循环超时),或者(可能更好)如果文件存在,则决定是否输出“Time over”消息。

答案2

另一种方法,避免了轮询的缺点(短轮询周期的资源消耗与长轮询周期的更改检测延迟之间的权衡)。付出的代价是它依赖于您可能无法使用的工具,即inotify 工具timeout(后者来自GNU Coreutils)。

假设“检查可用性”的含义是您正在等待fname创建一个文件(其名称在变量中):

timeout 3600 sh -c '
    if [ -e "$1" ]; then
        printf "%s is present already\n" "$1"
        exit
    fi
    while inotifywait -qq -e create dir; do
    if [ -e "$1" ]; then
        printf "%s present\n" "$1"
        exit
    fi
done' mysh "$fname"
[ "$?" -eq 124 ] && echo "Time over"

timeout在指定的持续时间内运行命令,这里是3600秒(s是默认的时间单位)。如果达到超时,timeout则以状态退出124;否则,它将退出并显示正在运行的命令的状态。

inotifywait等待目录的更改(应该在dir其中创建的目录);是我们正在关注的事件;真的很安静。$fnamecreate-qq

这种检查有时会被实现(例如在本网站的其他问答中):

inotifywait -m ... --format "%f" | while read -r file; do ...

其中-m(监视模式)防止inotifywait在第一个匹配事件之后退出,并且管道的右侧接收事件相关的文件的名称。不幸的是,如果文件名包含<newline>s,这种方法就会失效。

这就是为什么在上面显示的代码中,我们不使用-m而是检查$fname两次是否存在。这种方法有点脆弱,因为$fname 可能[ -e "$1" ]在第一次和第一次运行之间inotifywait(以及在执行之间)创建inotifywait。如果在监视目录中创建了大量文件,它也不太合适,因为每次执行都会inotifywait设置自己的监视。

答案3

以下脚本FILENAME在检查空输入时进行读取,END_DATE使用date命令进行计算,确保不超过一小时的挂钟时间,并FILENAME每秒检查是否存在名为 的文件INTERVAL。如果当前日期:

  • 等于 END_DATE:最后一次文件存在检查发生,脚本立即退出 while 循环(无需等待 300 秒)。
  • 超过 END_DATE: while 循环中断而不检查文件是否存在。
#!/usr/bin/env bash

echo -n "Enter file name to monitor: "

read FILENAME

if [ -z "${FILENAME}" ]
then
    echo -e "\nError: Filename is empty!\nExiting..."
    exit 1
fi

END_DATE=$(date --date='next hour' '+%s')
INTERVAL=300

FOUND="false"
while :
do
    CURRENT_DATE="$(date '+%s')"
    if [ "${CURRENT_DATE}" -gt "${END_DATE}" ]
    then
        break
    elif [ "${CURRENT_DATE}" -eq "${END_DATE}" ]
    then
        INTERVAL='0.1'   # Allow for one last check
    fi

    if [ -e "${FILENAME}" ]
    then
        FOUND="true"
        break
    fi
    sleep "${INTERVAL}"
done

if [ "${FOUND}" == "true" ]
then
    echo "${FILENAME} is present"
else
    echo "Time is Over"
fi

相关内容