Цикл while для проверки существования файла в bash


97

Я работаю над сценарием оболочки, который вносит определенные изменения в текстовый файл, только если он существует, однако этот тестовый цикл не работает, интересно, почему? Спасибо!

while [ ! -f /tmp/list.txt ] ;
do
      sleep 2
done

3
Не могу сказать, что я удивлен; этот цикл не пытается ничего изменить.
Игнасио Васкес-Абрамс,

Точка с запятой не указана. Каким образом этот тестовый цикл не работает? Он будет итеративно спать в течение 2 секунд, пока не появится файл /tmp/list.txt.
Джонатан Леффлер,

5
У меня работает - цикл завершается, когда файл создается вне скрипта.

1
на самом деле, этот цикл служит только для ожидания, пока файл не будет там, остальная часть моего скрипта вносит изменения ...: p
Zenet

1
Тогда цикл while работает, это только я ... извините.
Zenet

Ответы:


149

Когда вы говорите «не работает», откуда вы знаете, что это не работает?

Вы можете попытаться выяснить, существует ли файл на самом деле, добавив:

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]?
valentt

2
@valentt No hew loop, буквально «пока НЕ ​​существует файл, спи» .. если бы вы удалили «НЕ», цикл мгновенно
разорвался

2
в 1 строке:while [ ! -f /tmp/list.txt ]; do sleep 2; done; ls -l /tmp/list.txt
DrumM

55

Если вы используете linux и у вас установлены inotify-tools, вы можете сделать это:

file=/tmp/list.txt
while [ ! -f "$file" ]
do
    inotifywait -qqt 2 -e create -e moved_to "$(dirname $file)"
done

Это уменьшает задержку, вызванную спящим, при опросе каждые «x» секунд. Вы можете добавить больше событий, если считаете, что они необходимы.


4
+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 ];
do
    echo "#"
    sleep 1
done

Кроме того, если вы добавите эхо внутри цикла, оно сообщит вам, попадаете ли вы в цикл или нет.


2

Я столкнулся с аналогичной проблемой, и это привело меня сюда, поэтому я просто хотел оставить свое решение для всех, кто испытывает то же самое.

Я обнаружил, что если бы я запустил 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;

Надеюсь, это поможет кому-то сэкономить полчаса!


1

Как и у @ zane-hooper, у меня была аналогичная проблема с NFS. В параллельных / распределенных файловых системах задержка между созданием файла на одной машине и другой машиной, «видящей» его, может быть очень большой, поэтому я мог подождать целую минуту после создания файла до выхода из цикла while (и есть также последствие того, что он "видит" уже удаленный файл).

Это создает иллюзию, что сценарий «не работает» , в то время как на самом деле это файловая система бросает мяч.

Мне потребовалось время, чтобы понять, надеюсь, это кому-то сэкономит время.

PS Это также вызывает досадное количество ошибок "Обработчик устаревших файлов".


0

работает как с 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.."

0

Вот версия с тайм-аутом, так что по прошествии некоторого времени цикл завершается с ошибкой:

# 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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.