我写了这段代码。但问题是每 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
其中创建的目录);是我们正在关注的事件;真的很安静。$fname
create
-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