Wednesday, January 5, 2011

用 find、sed、xargs 及 mv 換檔名

用 find、sed、xargs 及 mv 換檔名
Posted in Links by jeffhung @ March 6th, 2009 |

用 UNIX,只要真的弄熟 find、sed、xargs 等工具,不用學什麼 scripting language,就已經可以處理大部分複雜的需求了。

話說我以前要更換延伸檔名的時候,指令大概都是這麼下的:

SHELL> find . -type f -name '*.vcproj' -print0 \
| sed -e 's/\.vcproj$//' \
| xargs -0 -n 1 -I @ mv @.vcproj @.vc9.vcproj \
;

首先先用 find 把所有要被更換的檔名列出來。然後,利用 sed 把延伸檔名的部份去掉。最後,利用 xargs 的 -I 功能[1],把讀入的部份用 @ 代表,組成 mv 指令:一個用 @.vcproj 把被 sed 去掉的部份還原,組成原來的路徑,另一個則用 @.vc9.vcproj 組合成想要的新檔名。

不過,先用 sed 把延伸檔名去掉,然後再加回來,有點脫褲子放屁。在我知道,原來 sed 的 -e 參數,可以連續使用,而其 p 指令,功能是原封不動地印出輸入的東西,我才發覺,上面的指令,其實可以寫成下面這樣:

SHELL> find . -type f -name '*.vcproj' \
| sed -e p -e 's/\.vcproj$/.vc9.vcproj/' \
| xargs -n2 mv \
;

一樣是先用 find 把所有要被更換的檔名列出來。接著,利用 sed 改造,分兩個 -e 給指令:先用 p 指令印出原來的檔名,然後在用 s/// 指令,將檔名改造成我們想要的樣子。

例如,現在有 a.vcproj、b.vcproj 與 c.vcproj 三個檔案要被更名,find 會得到這樣的資料:

a.vcproj
b.vcproj
c.vcproj

經過 sed -e p -e 's/\.vcproj$/.vc9.vcproj/' 處理後,會變成這樣:

a.vcproj
a.vc9.vcproj
b.vcproj
b.vc9.vcproj
c.vcproj
c.vc9.vcproj

其中,單數行是 sed 的 p 指令印出來的,雙數行是 s/// 指令印出來的。

如此一番,將找到的路徑,兩行為一組,餵給 xargs -n2 一次收兩行,就可以組合出如下的指令:

mv a.vcproj a.vc9.vcproj
mv b.vcproj b.vc9.vcproj
mv c.vcproj c.vc9.vcproj

新的更換檔名的方法,字數更少,亦不限於只能更換延伸檔名,彈性更佳。

1. -I 是 FreeBSD 上的 xargs 的參數,在 Linux 上,參數名稱不一樣。 ↩

Reference:
what is the difference between find -exec cmd {} + and xargs

No comments: