遞歸列出目錄,首先使用子路徑和葉節點(文件)(用於批量重命名文件名的一部分)?
在聲明它重複之前,請考慮我出於特定原因需要它:批量重命名(或複製到新名稱)包含文件和目錄名稱中的公共字元串的樹結構。這是一個範例(在 Ubuntu 14.04 上嘗試過,因此使用 GNU 工具):
cd /tmp mkdir myproj mkdir -p myproj/myproj_AA/myproj_BB touch myproj/myproj_AA/myproj_BB/myproj_CC.dat mkdir myproj/myproj_AA/myproj_DD touch myproj/myproj_AA/myproj_DD/myproj_EE.dat mkdir -p myproj/myproj_XX/myproj_YY touch myproj/myproj_XX/myproj_YY/myproj_ZZ.dat mkdir -p myproj/myproj_XX/myproj_WW touch myproj/myproj_XX/myproj_WW/myproj_QQ.dat tree myproj # to visualise
這個目錄結構
tree
看起來像這樣:myproj ├── myproj_AA │ ├── myproj_BB │ │ └── myproj_CC.dat │ └── myproj_DD │ └── myproj_EE.dat └── myproj_XX ├── myproj_WW │ └── myproj_QQ.dat └── myproj_YY └── myproj_ZZ.dat 6 directories, 4 files
所以,我希望 中的所有條目
myproj/
,包括myproj
它本身,都重命名為myTESTproj
而不是myproj
(無論它可能作為名稱出現在哪裡)。所以,首先我需要獲得一個相對於目前目錄的相對路徑列表 - 然後我需要對其進行排序,以便最外面的孩子(我認為這相當於具有最長相對路徑名的文件,但不確定)是第一個(因為如果我先重命名/mv 目錄,然後嘗試重命名其中的文件,它可能會使用舊的目錄名稱作為第一個參數,並且由於名稱現在已更改而失敗)。我知道首先
ls -R --group-directories-first myproj/
要使用ls
遞歸和組目錄,但它的輸出是這樣的:$ ls -R --group-directories-first myproj/ myproj/: myproj_AA myproj_XX myproj/myproj_AA: myproj_BB myproj_DD myproj/myproj_AA/myproj_BB: myproj_CC.dat myproj/myproj_AA/myproj_DD: myproj_EE.dat myproj/myproj_XX: myproj_WW myproj_YY myproj/myproj_XX/myproj_WW: myproj_QQ.dat myproj/myproj_XX/myproj_YY: myproj_ZZ.dat
…也就是說,它不是帶有子路徑的簡單列表,我可以輕鬆地提供給
while read f; do ...
我最接近的是使用
find
:$ find myproj/ myproj/ myproj/myproj_AA myproj/myproj_AA/myproj_DD myproj/myproj_AA/myproj_DD/myproj_EE.dat myproj/myproj_AA/myproj_BB myproj/myproj_AA/myproj_BB/myproj_CC.dat myproj/myproj_XX myproj/myproj_XX/myproj_YY myproj/myproj_XX/myproj_YY/myproj_ZZ.dat myproj/myproj_XX/myproj_WW myproj/myproj_XX/myproj_WW/myproj_QQ.dat
所以,在這裡我確實有一個簡單的子路徑列表,但是它首先向葉節點排序根節點 - 我首先需要葉節點。我正在嘗試類似的東西
find myproj/ | sort -n
,但似乎沒有什麼區別。因此,如果我執行以下操作:$ find myproj/ | sort -n | while read f; do mv -v $f $(echo $f | sed 's/myproj/myTESTproj/g'); done ‘myproj/’ -> ‘myTESTproj/’ mv: cannot stat ‘myproj/myproj_AA’: No such file or directory mv: cannot stat ‘myproj/myproj_AA/myproj_BB’: No such file or directory mv: cannot stat ‘myproj/myproj_AA/myproj_BB/myproj_CC.dat’: No such file or directory ...
…然後預期的遞歸重命名立即失敗,因為根節點(目錄)首先被重命名,因此對它的所有進一步引用都是無效的。
那麼,如何首先獲得帶有葉節點的子目錄的正確遞歸列表,以便像這樣在批量重命名中使用它?
如果您的目標只是重命名,那麼在目錄本身之前處理每個目錄的內容還不夠嗎,也就是說,您不需要首先(來自所有目錄)的所有葉子?正是這樣做的。
find -depth
$ mkdir -p a/b c/d $ find -depth ./a/b ./a ./c/d ./c .
然後您可以使用
find -exec
和 Bash 重命名文件:$ find -depth ! -name . -name "*myproj*" -execdir bash -c ' for f; do mv "$f" "${f/myproj/myTESTproj}" ; done' bash {} +
如果您安裝了 Perl 版本的
rename
命令(有時稱為prename
),這將適用於您find myproj -depth -name '*myproj*' -exec rename -n 's!(.*)myproj!$1myTESTproj!' {} +
確保任何目錄中的子項列在目錄本身之前的選項
-depth
。find
操作的+
後綴允許對指定命令的一次呼叫-exec
進行多次插入。{}
以降低效率為代價,您可以將其替換為\;
.當你確定它會做你想做的事時,刪除
-n
或替換它-v
。