使用單一 bash 指令批次重命名資料夾

使用單一 bash 指令批次重命名資料夾

我有這樣的資料夾設定:

/path/to/directory/SLUG_1/SLUG_1 - SLUG_2 - SLUG_3

SLUG_2 是年份,年份後面可能有字母,如“1994”或“2003a”。

我想將這些文件重命名為:

/path/to/directory/SLUG_1/SLUG_2 - SLUG_3

我已經非常接近這個命令了:

find $root -mindepth 2 -maxdeth 2 -type d | sed "s#\(\(/path/to/directory/[^/]*/\).* - \([0-9]\{4\}[a-bA-B]\? - .*\)\)#mv "\1" "\2\3"#

這列印:

mv "/path/to/directory/SLUG_1/SLUG_1 - SLUG_2 - SLUG_3" "/path/to/directory/SLUG_1/SLUG_2 - SLUG_3"

這正是我想要執行的命令。但我無法執行它。

我嘗試將輸出分配給變數並通過調用該變數來執行它。那行不通。我嘗試了這個想法的一些變體,但出現了錯誤。

感覺就像我在這裡缺少一些工具。一些迭代工具可以使這項工作變得容易。有什麼建議麼?

答案1

假設所有子目錄都/path/to/directory遵循該命名約定:

cd /path/to/directory
prename -n 's~/\d{4}[a-z]? - ~/~i' */*

prename是個Perl重新命名(任何變體都可以)。

答案2

這列印:

mv ...

這正是我想要執行的命令。但我無法執行它。

我嘗試將輸出分配給變數並通過調用該變數來執行它。那行不通。我嘗試了這個想法的一些變體,但出現了錯誤。

感覺就像我在這裡缺少一些工具。

您正在尋找的簡單方法是附加| bash到您的命令中。這就是如何從“列印命令的命令”到“實際運行列印的命令”。

但是,即使您在要列印的命令中包含雙引號,這是一個餿主意包含在腳本中。

您可能已經處理了空格方面的問題,但是如果檔案名稱直接包含雙引號字元怎麼辦?還是換行符號?或變數名(將在雙引號內展開)?

僅有的檔案名稱中非法的字元是斜線 ( /) 和空位元組。

在編寫腳本時,您應該保持比互動式命令列更高的穩健性標準。

在命令列中,您可以看到要執行的命令,可以確認它是否正確,然後可以執行它。在劇本中,沒有監督,也沒有確認。該腳本將執行您告訴它執行的操作,無論這可能會產生多大的破壞性。

所以正確的方法其實是使用find,詳見我的其他答案。這將處理任何檔案名稱正確且不包含任意程式碼執行漏洞。

答案3

另一個答案是使用 GNUfind來處理重命名。無論檔案名稱中包含哪些字符,此方法都很可靠。

如果我正確理解您的用例,您想要重新命名以其父目錄的全名開頭的目錄。換句話說,如果您的目錄是這樣命名的:

/some/path/abcdefghi/abcdefghi - something - else/

你想像這樣重命名它:

/some/path/abcdefghi/something - else/

由於您在這個問題上指定了 GNU 作為標籤,因此您可以使用該find命令的 GNU 擴充功能並按如下方式處理:

find . -mindepth 2 -maxdepth 2 -type d -regextype posix-egrep -regex '.*/([^/]+)/\1[^/]+' -exec sh -c 'new="$(sed -r "s:/([^/]+)/\\1 ?-? ?([^/]+)\$:/\\1/\\2:" <<<$1)"; mv "$1" "$new"' find-sh {} \;

檢測結果:

[vagrant@localhost test]$ mkdir -p SLUG_1/SLUG_{1\ -\ SLUG_{2..4}\ -\ SLUG_5,7\ -\ something}
[vagrant@localhost test]$ find . -type d
.
./SLUG_1
./SLUG_1/SLUG_1 - SLUG_2 - SLUG_5
./SLUG_1/SLUG_1 - SLUG_4 - SLUG_5
./SLUG_1/SLUG_1 - SLUG_3 - SLUG_5
./SLUG_1/SLUG_7 - something
[vagrant@localhost test]$ find . -mindepth 2 -maxdepth 2 -type d -regextype posix-egrep -regex '.*/([^/]+)/\1[^/]+' -exec sh -c 'new="$(sed -r "s:/([^/]+)/\\1 ?-? ?([^/]+)\$:/\\1/\\2:" <<<$1)"; mv "$1" "$new"' find-sh {} \;
[vagrant@localhost test]$ find . -type d
.
./SLUG_1
./SLUG_1/SLUG_3 - SLUG_5
./SLUG_1/SLUG_4 - SLUG_5
./SLUG_1/SLUG_2 - SLUG_5
./SLUG_1/SLUG_7 - something
[vagrant@localhost test]$ 

相關內容