Shell-Script

inotifywait 忽略監視目錄中的新文件夾

  • March 20, 2022

我正在嘗試使用 inotifywait 來觀看文件夾(/shares/Photos),當它檢測到添加到文件夾中的 jpg 時,我需要將其調整為子目錄($small_dir)。在照片目錄下會有很多 jpg 的子文件夾。

樹長這樣

shares
 -Photos
     -Folder 1
     -Folder 2
      .
      .
      .

基本上每當有人將圖片複製到folder 1我需要創建一個新的子文件夾,然後調整圖像大小並將較小的版本放入該文件夾中。

所以樹會變成:

shares
 -Photos
     -Folder 1
         -Resized
     -Folder 2
      .
      .
      .

到目前為止我的程式碼:

inotifywait -mr --timefmt '%m/%d/%y %H:%M' --format '%T %w %f' -e close_write /shares/Photos --includei "\.jpg|\.jpeg" |
while read -r date time dir file; do
   changed_abs=${dir}${file}
   small_dir=${dir}${target}/
   
   printf "\nFile $changed_abs was changed or created\n  dir=$dir \n  file=$file \n  small_dir=$small_dir \n"
   
   # Check if the $small_directory exists, if not create it.
   if [ -d "$small_dir" -a ! -h "$small_dir" ]
   then
       echo "$small_dir found, nothing to do."
   else
       echo "Creating $small_dir"
       mkdir $small_dir
       chmod 777 $small_dir
   fi
   
   # Check to see if the file is in $small_dir, if it is, do nothing.  
   if [ "$dir" = "$small_dir" ]; then
       printf "\nFile is in the $small_dir folder, nothing to do\n"
   else
       printf "\nResizing file into the $small_dir folder\n"
       # Code to resize the image goes here.
   fi
       
done

它主要工作,但我的頭撞牆的是,如果我Photos在腳本執行時創建一個新的子文件夾,inotifywait 只是忽略它並且什麼都不做。

我嘗試替換close_write為,create但沒有任何區別,我真的不確定從這裡去哪裡。

任何建議/幫助將不勝感激。

OP正在使用:

inotifywait -mr --timefmt '%m/%d/%y %H:%M' --format '%T %w %f' -e close_write /shares/Photos --includei "\.jpg|\.jpeg" |

關於--includei告訴的文件(粗體強調我的):

--includei <pattern>

僅為文件名與指定 POSIX 正則表達式匹配的文件子集處理事件,不區分大小寫。

那不是:“顯示事件”而是“處理事件”。實際上,這意味著只有名稱包含.jpgor的目錄的事件.jpeg才會被處理。

不會處理髮生但與過濾器不匹配的目錄創建事件,因此inotifywait不會呼叫inotify_add_watch(2)此事件以及稍後在 this 中發生的任何事情。因此,在這個子目錄中永遠不會有事件被監視。

我找不到使用--includei或其他類似選項來表達“僅針對這些正則表達式任何目錄處理事件”的方法。


更新:建議一種解決方法

所以讓它工作的方法似乎必須在命令之外進行過濾。grep如果不是 tty,GNU將緩衝它的輸出,所以添加--line-buffered.

這將受到使用者輸入的影響(如文件名中的空格)。為了緩解這種情況,/需要在目錄和文件名之間使用分隔符(在文件名中無效)。由於目錄部分方便地包含尾隨/,因此只需刪除格式字元串中的空格就足夠了(以及進一步的變數處理和重用,如changed_abs)。同時,我正在糾正過濾以字元串or結尾的文件名的意圖,不包括這些字元串,並可能改進對內部有空格的目錄的初始處理(的影響,但以後還有更多需要修復)。OP 應該真正用腳本中的引號保護所有相關變數(jpg``jpeg``changed_abs``small_dir``{ }不替換引號)。

代替:

inotifywait -mr --timefmt '%m/%d/%y %H:%M' --format '%T %w %f' -e close_write /shares/Photos --includei "\.jpg|\.jpeg" |
while read -r date time dir file; do
    changed_abs=${dir}${file}
    small_dir=${dir}${target}/

和:

inotifywait -mr --timefmt '%m/%d/%y %H:%M' --format '%T %w%f' -e close_write /shares/Photos |
   grep --line-buffered -Ei '/[^/]*\.(jpg|jpeg)$' |
while read -r date time changed_abs; do
   [ -d "$changed_abs" ] && continue # a directory looking like a picture filename was written to: skip this event
   dir="${changed_abs%/*}/"
   file="${changed_abs##*/}"
   small_dir="${dir}${target}/"

沒有完全測試,但這就是想法。我什至不確定是否需要目錄測試(它似乎從來沒有發生過close_write事件),但它不會受到傷害。


筆記

  • 如果不清楚,則必須為檢測到的每個目錄創建事件執行一個操作 ( inotify_add_watch(2)) ,必須盡快將一個新監視添加到該目錄,因為它可能會失去其中的後續事件(競爭條件)。它甚至記錄在BUGS部分:inotifywait``inotifywait

遞歸目錄監視程式碼中存在競爭條件

$$ … $$可能無法修復。

  • 較新版本的inotifywait,當至少在核心> = 5.9 上以 root (或足夠特權)執行時,應該能夠使用該fanotify(7)工具,但我無​​法設法讓我的版本inotifywait使用它,儘管應該是在支持下編譯並具有足夠新的核心。在fanotify(7)將要使用的系統上,結合該--filesystem選項,假設這可以消除必須為每個較新目錄執行操作的需要,並使 OP 的方法基於過濾--includei工作。

引用自:https://unix.stackexchange.com/questions/696128