我想使用parallel
或使用其他工具或方法將許多目錄並行拆分為子目錄。
例如,我有 1 000 000 個包含內容的目錄,但對於一個目錄來說太多了,所以我想在主目錄中建立 10 個目錄,並在每個目錄中移動 100 000 個原始目錄。我還想使用按日期排序。我已經問過了類似的問題在這裡,但這並不重複,因為我嘗試了新命令,得到了新結果,現在我重新提出了問題。
所以,我已經嘗試過這個
ls -tr|parallel -n100000 mkdir "dir_{#}"\;mv {} "dir_{#}"
和這個
ls -tr | parallel -j10 -n100000 --no-notice -k 'mkdir -p dir_{#}; mv {} -t dir_{#}'
命令,但它只將 ~10 000 移動到一個子目錄中(有時 ~6200,有時 ~12 500)並創建太多子目錄 - 有時比我需要的多 10 倍。
我也嘗試使用這個:
ls -dtr * | parallel -j10 -n100000 --no-notice -k 'mkdir -p dir_{#}; mv {} -t dir_{#}'
但它給了bash: /bin/ls: Argument list too long
。
當然,我不需要每個子目錄中正好有100 000個目錄,它可以是101 000或98 500個目錄,它應該是100 000範圍內的數字
我如何並行或使用執行此任務parallel
?
答案1
問題是 shell 擴充後命令列可以佔用的位元組數有上限,這個限制取決於系統的限制
getconf ARG_MAX
mv {}
因此,只要達到最大限制,參數的數量就會根據輸入檔名的長度而改變。
避免這種限制同時不放棄使用並行的解決方案是將任務分為兩個階段
ls -tr | parallel -N 100000 --pipe -k "mkdir dir_{#}; parallel -X mv -t dir_{#}"
說明
第一階段使用選項
--pipe
將標準輸入拆分為確定數量的較小的標準輸入,每行包含由選項指定的 n 行-N
。您可以透過這個例子觀察一下效果seq 1000000 | parallel -N 100000 --pipe wc -l
給出了 100000 處的精確分割
100000 100000 100000 ...
在第二階段,內部平行採取較小的標準輸入作為執行作業的新標準輸入,該
-X
選項會插入命令列長度允許的盡可能多的參數mkdir dir_{#}; parallel -X mv -t dir_{#}
答案2
這個問題涉及大量IO。我懷疑這parallel
在這種情況下是否真的有用。
無論如何,我建議您考慮“傳統”方法:
mkdir dir_{1..10}
ls -tr | nl | \
awk '$2 !~ /^dir_/ {i=1+int($1/100000); print $2 | "xargs mv -t dir_"i}'
在哪裡
ls -tr | nl
按日期對目錄進行排序並新增輔助目錄號$2 !~ /^dir_/
用於跳過剛剛建立的資料夾。i=1+int($1/100000)
根據目錄號計算資料夾的編號print $2 | "xargs mv -t dir_"i
移動時無需進程擴散
如果可能的話,也比較各自的時間:(time ....
並與我們分享結果☺)