я написал этот код. но проблема в том, что после каждых 300 с он печатает "Time over", когда $fname present выводится из цикла. Я хочу, чтобы "time over" через 1 час, если файл не прибыл, но после 300 с он начинает печатать "time over"
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
) превысила границу (указывает на то, что истекло время ожидания цикла), или, как вариант (может быть, даже лучше), если файл присутствует, чтобы решить, выводить ли сообщение «Время истекло».
решение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