Что происходит, когда файлы добавляются/удаляются в середине цикла sh «for f in *»?

Что происходит, когда файлы добавляются/удаляются в середине цикла sh «for f in *»?

Я нашел один пример цикла for в сети. Теперь я хочу использовать его в своем коде, но я не уверен, как работает этот цикл

for entry in "$search_dir"/* 
do
  echo "$entry"
done

Теперь я хочу спросить, что

  1. Просматривает ли он search_dir в каждой итерации и копирует ли файлы из search_dir в переменную entry по одному файлу в каждой итерации?
  2. Или мне сделать снимок всего содержимого search_dir и затем сохранить этот снимок в переменной entry?
  3. Изменится ли вывод, если кто-то вставит файл в search_dir, пока цикл все еще работает?

решение1

Когда оболочка доходит до -statement for, она расширяет значение $search_dirи выполняет подстановку имени файла, чтобы сгенерировать список записей каталога, которые будут перебраны. Это происходит только один раз, и если что-то в $search_dirисчезает или если в этот каталог добавляются новые файлы/каталоги во время выполнения цикла, эти изменения не будут учтены.

Если цикл работает с записями каталога, имена которых находятся в $entry, может возникнуть необходимость проверить их наличие в цикле, особенно если известно, что цикл выполняется долго и имеется много файлов, которые по той или иной причине постоянно изменяются:

for entry in "$search_dir"/*; do
    if [ -e "$entry" ]; then
        # operate on "$entry"
    else
        # handle the case that "$entry" went away
    fi
done

Как справедливо отмечает Стефан в комментариях, это излишний тестбольшинствослучаи.

решение2

Оболочка полностью определяет список значений для цикла, прежде чем начнет выполнять тело цикла. То есть:

  1. Оболочка строит путь, используя значение переменной search_dir.
  2. Оболочка собирает список имен файлов в указанном каталоге, чтобы создать список совпадений с шаблоном подстановочных знаков.
  3. Оболочка выполняет тело цикла по очереди с каждым элементом списка совпадений.

Вы можете изменить значение переменной search_dirи изменить содержимое каталога во время выполнения цикла. Это не повлияет на то, какие файлы обрабатывает цикл.

Если файл удаляется, пока цикл обрабатывает другие файлы, то как только он доберется до этого файла, этот файл не будет существовать. В зависимости от того, что вы делаете в цикле, это может иметь значение или нет. Если есть параллельный процесс, который может удалять файлы, обратите внимание, что проверка существования файла перед его обработкой на самом деле не решит эту проблему, так какфайл может быть удален между временем тестирования и временем начала обработки.

Если вам нужно пометить файл как обработанный, чтобы убедиться, что вы не обрабатываете его дважды, то этот скрипт должен переместить файлы в другой каталог после их обработки. Перемещение файла в другой каталог (в той же файловой системе)атомный: либо это еще не сделано, либо это сделано, промежуточного состояния нет. Но еще раз, еслидругойпроцесс (возможно, другой экземпляр этого скрипта) перемещает файлы, то цикл иногда будет затрагивать файлы, которые перемещаются во время выполнения цикла.

Если вы хотите обрабатывать новые файлы по мере их создания, вам нужно будет снова выполнить цикл. Очевидно, что файлы могут быть созданы во время выполнения цикла или после того, как все предыдущие файлы были обработаны, поэтому скрипт должен будет продолжать работать вечно. Существуют инструменты для ожидания, пока файл не будет создан в каталоге. В Linux базовая возможность для этого —inotify; если вам необходимо обрабатывать файлы по мере их создания, тоinotifywaitилиинкрондолжно помочь вам. Помните, что inotify уведомляет вас только о созданных файлах (или измененных или полученных в зависимости от вашего триггера)послезапускаются команды на основе inotify; вам также нужно будет позаботиться о ранее существующих файлах, и вы не сможете сделать это просто так, for entry in *; do …; done; inotifywait …поскольку файлы могут быть созданы во время выполнения цикла или даже во время inotifywaitзапуска команды.

Связанный контент