Цикл while для проверки существования файла в bash
97
Я работаю над сценарием оболочки, который вносит определенные изменения в текстовый файл, только если он существует, однако этот тестовый цикл не работает, интересно, почему? Спасибо!
Не могу сказать, что я удивлен; этот цикл не пытается ничего изменить.
Игнасио Васкес-Абрамс,
Точка с запятой не указана. Каким образом этот тестовый цикл не работает? Он будет итеративно спать в течение 2 секунд, пока не появится файл /tmp/list.txt.
Джонатан Леффлер,
5
У меня работает - цикл завершается, когда файл создается вне скрипта.
1
на самом деле, этот цикл служит только для ожидания, пока файл не будет там, остальная часть моего скрипта вносит изменения ...: p
Zenet
1
Тогда цикл while работает, это только я ... извините.
Zenet
Ответы:
149
Когда вы говорите «не работает», откуда вы знаете, что это не работает?
Вы можете попытаться выяснить, существует ли файл на самом деле, добавив:
while [ ! -f /tmp/list.txt ]
do
sleep 2 # or less like 0.2done
ls -l /tmp/list.txt
Вы также можете убедиться, что используете оболочку Bash (или связанную с ней), набрав «echo $ SHELL». Я думаю, что CSH и TCSH используют немного другую семантику для этого цикла.
+1 за эффективность. Объединение со сном уродливо. Для людей, не знающих inotifywait - он находится в пакете inotify-tools.
Михал Шрайер,
7
Это очень удобный инструмент. Для тех, кто задается вопросом, почему цикл, он связан с возможными условиями гонки между созданием и ожиданием, и потому что inotifywait должен --excludeотфильтровывать имена файлов, но не --includeигнорировать все, кроме имени файла. В приведенной выше команде следует использовать -qqаргумент, а не >&/dev/nullхотя.
Craig Ringer
это --timeoutне частота проверок, не так ли? Суть inotifywait в том, что опроса нет
Алекс Дин
1
@AlexDean Тайм-аут предназначен для предотвращения состояния гонки. Опрос в режиме сна выполняется медленно, потому что цикл не завершается во время сна, но inotifywait выйдет до истечения времени ожидания, если увидит событие.
yingted
1
@AlexDean Да, но это необходимо для предотвращения состояния гонки TOCTTOU. В противном случае inotifywaitможет зависнуть на неопределенное время, если файл создается непосредственно перед началом прослушивания событий.
yingted
4
У меня была такая же проблема, поставил! вне скобок;
while ! [ -f /tmp/list.txt ];
doecho"#"
sleep 1
done
Кроме того, если вы добавите эхо внутри цикла, оно сообщит вам, попадаете ли вы в цикл или нет.
Я столкнулся с аналогичной проблемой, и это привело меня сюда, поэтому я просто хотел оставить свое решение для всех, кто испытывает то же самое.
Я обнаружил, что если бы я запустил cat /tmp/list.txtфайл, он был бы пустым, хотя я был уверен, что содержимое сразу помещается в файл. Оказывается, если я поставил sleep 1;непосредственно перед этим, cat /tmp/list.txtон работал, как ожидалось. Должна была быть задержка между временем создания файла и временем его записи, или что-то в этом роде.
Мой последний код:
while [ ! -f /tmp/list.txt ];
do
sleep 1;
done;
sleep 1;
cat /tmp/list.txt;
Как и у @ zane-hooper, у меня была аналогичная проблема с NFS. В параллельных / распределенных файловых системах задержка между созданием файла на одной машине и другой машиной, «видящей» его, может быть очень большой, поэтому я мог подождать целую минуту после создания файла до выхода из цикла while (и есть также последствие того, что он "видит" уже удаленный файл).
Это создает иллюзию, что сценарий «не работает» , в то время как на самом деле это файловая система бросает мяч.
Мне потребовалось время, чтобы понять, надеюсь, это кому-то сэкономит время.
PS Это также вызывает досадное количество ошибок "Обработчик устаревших файлов".
Вот версия с тайм-аутом, так что по прошествии некоторого времени цикл завершается с ошибкой:
# After 60 seconds the loop will exit
timeout=60
while [ ! -f /tmp/list.txt ];
do# When the timeout is equal to zero, show an error and leave the loop.if [ "$timeout" == 0 ]; thenecho"ERROR: Timeout while waiting for the file /tmp/list.txt."exit 1
fi
sleep 1
# Decrease the timeout of one
((timeout--))
done
Ответы:
Когда вы говорите «не работает», откуда вы знаете, что это не работает?
Вы можете попытаться выяснить, существует ли файл на самом деле, добавив:
while [ ! -f /tmp/list.txt ] do sleep 2 # or less like 0.2 done ls -l /tmp/list.txt
Вы также можете убедиться, что используете оболочку Bash (или связанную с ней), набрав «echo $ SHELL». Я думаю, что CSH и TCSH используют немного другую семантику для этого цикла.
источник
while [ ! -f /tmp/list.txt ]; do sleep 2; done; ls -l /tmp/list.txt
Если вы используете linux и у вас установлены inotify-tools, вы можете сделать это:
file=/tmp/list.txt while [ ! -f "$file" ] do inotifywait -qqt 2 -e create -e moved_to "$(dirname $file)" done
Это уменьшает задержку, вызванную спящим, при опросе каждые «x» секунд. Вы можете добавить больше событий, если считаете, что они необходимы.
источник
--exclude
отфильтровывать имена файлов, но не--include
игнорировать все, кроме имени файла. В приведенной выше команде следует использовать-qq
аргумент, а не>&/dev/null
хотя.--timeout
не частота проверок, не так ли? Суть inotifywait в том, что опроса нетinotifywait
может зависнуть на неопределенное время, если файл создается непосредственно перед началом прослушивания событий.У меня была такая же проблема, поставил! вне скобок;
while ! [ -f /tmp/list.txt ]; do echo "#" sleep 1 done
Кроме того, если вы добавите эхо внутри цикла, оно сообщит вам, попадаете ли вы в цикл или нет.
источник
Я столкнулся с аналогичной проблемой, и это привело меня сюда, поэтому я просто хотел оставить свое решение для всех, кто испытывает то же самое.
Я обнаружил, что если бы я запустил
cat /tmp/list.txt
файл, он был бы пустым, хотя я был уверен, что содержимое сразу помещается в файл. Оказывается, если я поставилsleep 1;
непосредственно перед этим,cat /tmp/list.txt
он работал, как ожидалось. Должна была быть задержка между временем создания файла и временем его записи, или что-то в этом роде.Мой последний код:
while [ ! -f /tmp/list.txt ]; do sleep 1; done; sleep 1; cat /tmp/list.txt;
Надеюсь, это поможет кому-то сэкономить полчаса!
источник
Как и у @ zane-hooper, у меня была аналогичная проблема с NFS. В параллельных / распределенных файловых системах задержка между созданием файла на одной машине и другой машиной, «видящей» его, может быть очень большой, поэтому я мог подождать целую минуту после создания файла до выхода из цикла while (и есть также последствие того, что он "видит" уже удаленный файл).
Это создает иллюзию, что сценарий «не работает» , в то время как на самом деле это файловая система бросает мяч.
Мне потребовалось время, чтобы понять, надеюсь, это кому-то сэкономит время.
PS Это также вызывает досадное количество ошибок "Обработчик устаревших файлов".
источник
работает как с bash, так и с sh:
touch /tmp/testfile sleep 10 && rm /tmp/testfile & until ! [ -f /tmp/testfile ] do echo "testfile still exist..." sleep 1 done echo "now testfile is deleted.."
источник
Вот версия с тайм-аутом, так что по прошествии некоторого времени цикл завершается с ошибкой:
# After 60 seconds the loop will exit timeout=60 while [ ! -f /tmp/list.txt ]; do # When the timeout is equal to zero, show an error and leave the loop. if [ "$timeout" == 0 ]; then echo "ERROR: Timeout while waiting for the file /tmp/list.txt." exit 1 fi sleep 1 # Decrease the timeout of one ((timeout--)) done
источник
делай это так
while true do [ -f /tmp/list.txt ] && break sleep 2 done ls -l /tmp/list.txt
источник