我寫了這段程式碼。但問題是每 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