Linux rename命令 批量重命名

Linux的 rename 命令有兩個版本,一個是C語言版本的,一個是Perl語言版本的,早期的Linux發行版基本上使用的是C語言版本的,現在已經很難見到C語言版本的了,由於歷史原因,在Perl語言大紅大紫的時候,Linux的工具開發者們信仰Perl能取代C,所以大部分工具原來是C版本的都被Perl改寫了,因爲Perl版本的支持正則處理,所以功能更加強大,已經不再需要C語言版本的了。
 

如何區分系統裏的rename命令是哪個版本的?

輸入 man rename 看到第一行是

RENAME(1) Linux Programmer’s Manual RENAME(1)

那麼 這個就是C語言版本的。

而如果出現的是:
RENAME(1)              Perl Programmers Reference Guide              RENAME(1)

這個就是Perl版本的了!


兩個版本的語法差異:

C語言的,按照man上面的註解,
rename的語法格式是:

rename
fromtofile

這個命令有三個參數,分別是 from : 修改什麼名字, to:改成什麼名字, file 需要修改的文件是哪些。

用法示例:
比如,有一批文件,都是以 log開頭的, log001.txt,  log002.txt ....... 一直到 log100.txt
現在想要把這批文件的log全部替換爲 history
rename 
log history log*

這句命令的意思很明白了,把 以 log開頭的所有文件中的 log字符替換爲 history
這樣替換後的文件是: history001.txt,  history002.txt ..... 一直到 history100.txt

rename C語言版本的另一個man示例是把後綴名批量修改,
比如我們要將所有 jpeg的後綴名圖片文件修改爲 jpg文件。

rename
.jpeg.jpg*.jpeg

這樣,所有以 .jpeg擴展的後綴名全部被修改爲 .jpg

現在總結一下rename C語言版本所能實現的功能: 批量修改文件名,結果是每個文件會被用相同的一個字符串替換掉!也就是說,無法實現諸如循環 然後按編號重命名!



2, Perl 版本的批量重命名,帶有Perl的好處是,你可以使用正則表達式來完成很奇特的功能。

perl 版本的參數格式:

rename 
perlexprfiles

注意,perl版本的rename只有兩個參數,第一個參數爲perl正則表達式,第二個參數爲所要處理的文件

man rename的幫助示例:

1) 有一批文件,以 .bak結尾,現在想把這些 .bak 統統去掉。

rename    
's/\.bak$//'       *.bak

這個命令很簡單,因爲我還沒有系統學習過perl,我不知道perl裏替換字符串是不是這麼幹的,但sed是這麼幹的,所以如果你有sed或者tr基礎,很容易明白,這個替換和sed裏的正則語法是一模一樣的。

2) 把所有文件名內含有大小字母的,修改爲小寫字母。

rename     
'y/A-Z/a-z/'      *

依然和sed的替換語法一樣,不用多解釋,如果看不懂的話,可以系統學習一下sed先。

還有幾個比較實用的例子:

1) 批量去掉文件名裏的空格
Linux文件名本來是不支持空格的,不知道什麼時候允許了,當然,在命令行調用文件的時候,空格是很有問題滴,比如你 原來可以直接  mv  oldfile  newfile  但有空格就不行了 , 得加雙引號: mv "oldfile"  "newfile" 或者用反斜槓轉移  \[] ,這樣還好,但如果你直接把含有空格的圖片名引入 Latex文檔,Latex生成pdf的時候會直接打印出文件名,之前這個問題苦惱了我很久,我生成的pdf怎麼老是出現文件名呢?後來才發現原來是文件名內含有空格的問題!windows系統下生成的文件名是天生含有空格的,雖然很討厭,但有些惠普掃描儀生成的圖片默認就加入了空格,沒有辦法,只好去掉他,在系統研究rename命令前,我是用 mv 去除空格的。

網上流程的兩個去空格的版本:

1) tr 版:

find . -type f -name "* *" -print |
while read name; do
na=$(echo $name | tr ' ' '_')
if [[ $name != $na ]]; then
mv "$name" $na
fi
done


這個版本以前我一直用的,不知道哪個網上搜刮來的,當時還沒有系統的學習過 tr/sed/awk命令。
註解一下,很好理解, find . type f -name "* *" -print 這一句是查找當前目錄下所有類型爲普通文件的 並且名字之中含有空格的文件,並打印出來,其實 find默認就是打印的 這個 -print 多餘了,然後 通過管道傳輸給 while 循環讀取,文件名放到 name 變量裏,用 tr 命令 替換空格爲 下劃線。 下面判斷如果執行後的名稱不相同,使用 mv 命令重命名。但這個if判斷可有可無,因爲find已經查詢了所有文件名中含有空格的,那麼經過 tr 命令後, $na變量肯定不等於 $name 變量的。

所以這段代碼可以簡化:

find . -type f -name "* *" |
while read name; do
na=$(echo $name | tr ' ' '_')
mv "$name" "$na"
done


tr 可以看着是 sed 的一個精簡版本,tr 用下劃線來替換空格。

還有一個 是 sed 版本實現:

for f in *;do mv "$f" `echo "$f" | sed 's/[ ]\+/_/g' `; done

這裏的 sed表達式還可以這樣寫:

sed 's/[[:space:]]\+/_/g'

不過記住,sed裏的出現一次或多次的加號是需要添加反斜槓的。即:\+

這樣就可以了。

好了,這兩種辦法都太他媽羅嗦了,看看rename實現吧:

rename     
's/[ ]+/_/g'       *

OK就這麼簡單。
方括號內的空格可以用 [:space:]代替,
即可以寫成 's/[[:space:]]+/_/g'

這裏注意,rename 採用的是標準perl正則語法,所以無須將 加號轉變爲反斜槓加號
即 + 不能修改爲 \+,否則替換失敗。


還有幾個好玩的例子:
比如統一在文件頭部添加上 hello 
rename         's/^/hello/'       *

統一把.html擴展名修改爲 .htm
rename          's/.html$/.htm/'      *

統一在尾部追加 .zip後綴:
rename          's/$/.zip/'      *

統一去掉.zip後綴:
rename          's/.zip$//'      *
 
規則化數字編號名,比如 1.jpg, 2.jpg ..... 100.jpg , 現在要使文件名全部三位即 1.jpg .... 001.jpg
運行兩次命令:
rename           's/^/00/'          [0-9].jpg     # 這一步把 1.jpg ..... 9.jpg 變幻爲 001.jpg .... 009.jpg
rename            's/^/0/'           [0-9][0-9].jpg   # 這一步把 10.jpg ..... 99.jpg 變幻爲 010.jpg ..... 090.jpg

Ok ,rename就研究了這麼多,暫時不知道如何在rename中引入動態變量,比如 $i++

我測試過 i=0;  rename -n "s/^.*$/$((++i))/"   *  執行後i被自增了1,並非想我想像中那樣,可以在每操作一個文件自增一,猜想可能是因爲rename批量實現的,導致++i只計算一次!


-n 用來測試rename過程,並不直接運行,可以查看測試效果後,然後再運行。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章