並行查詢重新運行循環腳本

並行查詢重新運行循環腳本

我在 shell 腳本中有以下內容:

for file in $local_dir/myfile.log.*; 
    do 
        file_name=$(basename $file); 
        server_name=$(echo $file_name | cut -f 3 -d '.');
        file_location=$(echo $file);

        mv $file_location $local_dir/in_progress1.log

        mysql -hxxx -P3306 -uxxx -pxxx -e "set @server_name='${server_name}'; source ${sql_script};"

        rm $local_dir/in_progress1.log
    done

它基本上會取得目錄中符合條件的所有文件,從文件名中提取伺服器名,然後將其傳遞給 MySQL 腳本進行處理。

我想知道是否有 10 個文件,每個文件需要 60 秒才能完成,5 分鐘後我啟動 shell 腳本的第二個實例:

  • a) 第二個腳本是否仍會看到尚未處理的文件
  • b) 如果刪除文件,第一次會導致問題嗎

或者我可以毫無問題地並行運行它們嗎?

答案1

人們會認為「60秒」(甚至「5分鐘」)只是一個不錯的估計,並且存在當第二批開始時第一批仍在進行中的風險。如果您想分隔批次(並且除了偶爾重疊的日誌檔案之外沒有問題),更好的方法是將批次號碼作為正在進行的檔案命名約定的一部分。

像這樣的東西:

[[ -s ]] $local_dir/batch || echo 0 > $local_dir/batch
batch=$(echo $local_dir/batch)
expr $batch + 1 >$local_dir/batch

在 for 循環之前,然後在循環開始時,檢查您的模式是否與實際文件匹配

[[ -f "$file" ]] || continue

並在檔案名稱中使用批號:

mv $file_location $local_dir/in_progress$batch.log

往復。這降低了碰撞的風險。

答案2

上面有一個答案為該問題提供了一些很好的解決方案,但我想我應該提供一些解釋為什麼問題是什麼。

大多數情況下:只要您重新命名的日誌檔案(正在進行的日誌檔案)不符合標準,您就可以大概可以安全地運行它最小的風險。但你還是會遇到一些錯誤...

您的文件清單是在腳本執行時產生的。所以最終會發生的是:

Script A取得 的列表10 files。開始處理,5 files在(剩餘5)中script B得到一個列表5 remaining files,開始處理。Script a然後去處理其列表中的下一個文件(與文件已開始處理的相同script B),它將出錯,因為文件已被重新命名。因此,透過錯誤處理,理論上它可以毫無問題地轉到其列表和函數中的下一個。但是,顯然總是有機會對齊星星,但腳本同時擊中同一個文件,並且會發生意想不到的事情。隨意權衡風險。

一種可能更優雅的解決方案是將其轉換為python腳本,並研究parallel for loops它允許您創建單個 for 循環,並並行運行它,從而允許一個腳本完成兩個或多個腳本的工作。

答案3

另一種方法是在腳本中實作一個簡單的批次佇列。

在腳本的開頭,您可以執行以下操作:

mkdir -p $localdir/batch
BATCHTMP=$(mktemp batch.XXXXXXXXXX)
MYBATCH="$localdir/batch/batch.$$"

# get list of current log files
find $local_dir/ -name 'myfile.log.*' > "$BATCHTMP"

# exclude any log files already in other batches
grep -vF -f <(sort -u $localdir/batch/batch.*) < "$BATCHTMP" > "$MYBATCH"

rm -f "$BATCHTMP"

# only process log files that are in my batch
for lf in $(cat "$MYBATCH") ; do
....
# somewhere in here, mv or rm the logfile being processed
# so it doesn't get processed again in a later batch run
done

rm -f "$MYBATCH"

當然,這只是需要做的事情的簡單概述。

順便說一句,這也可以在包裝腳本中完成,該腳本除了生成批次文件然後運行主腳本之外什麼也不做。

相關內容