Почему этот inotifywait shellscript делает покупки с двумя PID?

Я учусь использовать inotifywait, в частности, используя скрипт по адресу: https://unix.stackexchange.com/questions/24952/script-to-monitor-folder-for-new-files. Что я не понимаю, так это то, почему мои скрипты всегда появляются два раза, когда я использую pid x,

36285 pts/1    S+     0:00 /bin/bash ./observe2.sh /home/user1/testfolder
36286 pts/1    S+     0:00 inotifywait -m /home/user1/testfolder -e create -e moved_to
36287 pts/1    S+     0:00 /bin/bash ./observe2.sh /home/user1/testfolder

Для более быстрого тестирования я изменил связанный скрипт, чтобы вы могли пропустить любую папку через $1, чтобы ее можно было наблюдать и сохранить как observe2.sh:

#!/bin/bash
inotifywait -m $1 -e create -e moved_to |
    while read path action file; do
        echo "The file '$file' appeared in directory '$path' via '$action'"
        # do something with the file
    done

Почему процесс сценария появляется два раза? Есть ли где-то вилка в процессе? Может ли кто-нибудь объяснить, почему именно происходит такое поведение двух процессов?

1 ответ

Решение

Потому что у него есть трубопровод.

Трубопровод разветвляется на подоболочку - второй процесс - и соединяет их. В случае foo | bar - где это обе внешние команды, не являющиеся оболочкой, - подоболочки exec фактические команды, и, таким образом, теряют свои записи дерева процессов. Когда элемент этого конвейера записан в оболочке, оболочка для его выполнения остается в дереве процессов.


Тем не менее, я бы предложил[1] написать это немного по-другому:

while read -r path action file; do
    echo "The file '$file' appeared in directory '$path' via '$action'"
    # do something with the file
done < <(exec inotifywait -m "$1" -e create -e moved_to)

Это сохранит цикл while в основном процессе, а exec заставляет расколотую подоболочку заменяться inotifywait, Таким образом, изменения, которые вы делаете внутри while Цикл, такой как установка переменных в вашем сценарии, будет сохраняться даже после того, как сценарий будет перемещен из цикла, тогда как если вы поместите цикл в конвейер, все переменные, заданные в нем, будут видны в подоболочке. Смотрите BashFAQ #24 для деталей.


[1] - На самом деле, я бы посоветовал написать это даже по-другому, если вы хотите полностью охватить все угловые дела. Так как имена файлов POSIX могут содержать любой символ, кроме NUL или / (а также / может, конечно, существовать в путевых именах), разделять пробелами или символами новой строки - очень плохая идея; в существующей реализации также есть ошибки, связанные с именами, заканчивающимися пробелами. К сожалению, так как inotifywait не позволяет содержать строки нестандартного формата \0 NUL-разграничить их, получить совершенно однозначный вывод из этого довольно сложно; это было рассмотрено в других ответах на Stackru, и я не сильно склонен воспроизводить их содержимое здесь.

Другие вопросы по тегам