Linux的rename 命令有兩個版本,一個是C語言版本的,一個是Perl語言版本的,早期的Linux發行版基本上使用的是C語言版本的,現在已經很難見到C語言版本的了,由於歷史原因,在Perl語言大紅大紫的時候,Linux的工具開發者們信仰Perl能取代C,所以大部分工具原來是C版本的都被Perl改寫了,因為Perl版本的支持正則處理,所以功能更加強大,已經不再需要C語言版本的了。
1。如何區分系統裡的rename命令是哪個版本的?
輸入man rename 看到第一行是
RENAME(1) Linux Programmer’s Manual RENAME(1)
那麼 這個就是C語言版本的。【我查看系統上應該就是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*【C的用法~】
這句命令的意思很明白了,把 以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過程,並不直接運行,可以查看測試效果後,然後再運行。
好了,再次說明一下,你在使用的時候一定要確認一下你語言的版本,我的是C語言版本~
RENAME(1) Linux Programmer’s Manual RENAME(1)
功能:
rename from to file...
用法:
For example, given the files foo1, ..., foo9, foo10, ..., foo278, the commands
rename foo foo0 foo?
rename foo foo0 foo??
will turn them into foo001, ..., foo009, foo010, ..., foo278.
And
rename .htm .html *.htm
will fix the extension of your html files.
下面來看一個例子:
最後再來個實際應用當中的問題,先看下以下的圖~
看到了吧,我們想把那個圖片文件名中的ad字母換成big【注意:拷貝一份,不能直接替換】,那麼想想該怎麼做呢,對了,就是用rename~
cd /data/openshop_1028/IMG_SERVER/sources/goods/
find ./ -name "*_ad.jpg" -exec cp "{}" {}.1 \;
find ./ -name "*_ad.jpg.1" -exec renamead.jpg.1 big.jpg {} \;
假如要是能夠直接替換的話,那就一條命令了:
cd /data/openshop_1028/IMG_SERVER/sources/goods/
find ./ -name "*_ad.jpg" -exec rename ad big {} \;
可以看以下的測試~
作者zhuying_linux