2012年9月19日 星期三

Linux 大量更改檔名

Linux 大量更改檔名

在Windows 的系統底下,如果要更改檔名或是副檔名都算是蠻簡單的動作,只要開啟cmd.exe,輸入指令就會把全部的jpg都改成gif,簡單的一行指令就搞定。

c:\>ren *.jpg *.gif



但是在Linux下呢,"*" 這個符號在使用mv指令的時候並無法當成萬用字元來看待,假設我用一樣的語法更改附檔名,會得到什麼結果呢?


ls(小寫的LS)的指令查詢看有哪些檔案,得知在這個目錄下有a-01.jpg ~ a-10.jpg
-----------------------------------------------------------------------------------------------------------
linux@linux:/$ ls 
a-01.jpg  a-03.jpg  a-05.jpg  a-07.jpg  a-09.jpg
a-02.jpg  a-04.jpg  a-06.jpg  a-08.jpg  a-10.jpg
-----------------------------------------------------------------------------------------------------------


用一樣的語法執行mv
-----------------------------------------------------------------------------------------------------------
linux@linux:/$  mv *.jpg *.gif
mv: cannot stat `*.jpg': No such file or directory
-----------------------------------------------------------------------------------------------------------
mv表示:無法確認 *.jpg 是一個檔案或是目錄夾,我不能下一步了。(廢話.........)


為什麼會變成這樣呢? 剛才已經說過了,"*" 這個符號在使用mv指令的時候並無法當成萬用字元來看待,*會變成普通字元,在目錄下並沒有 *.jpg 這個檔案存在,所以mv指令宣告失敗!

假設檔案數量很少,可能在10以下,那用手動更改還說的過去,但如果今天是50個,甚至到100個、1000個呢?難道也要一一更改嗎? 還沒等你改完,老闆的眼神就會像海上的探照燈一樣直直的投射在你身上。


廢話不多說,既然mv指令不管用,生命總是會自動找到出路的(喂,這是哪招阿!)。
歐,不! 我的意思是說山不轉路轉,mv不管用就改用rename吧。

rename表示:躺著也被挖出來....................


先看一下說明和使用的語法
-----------------------------------------------------------------------------------------------------------
linux@linux:/$ man rename
-----------------------------------------------------------------------------------------------------------


rename的使用說明內容
-----------------------------------------------------------------------------------------------------------

RENAME(1)              Perl Programmers Reference Guide              RENAME(1)

NAME
       rename - renames multiple files

SYNOPSIS
       rename [ -v ] [ -n ] [ -f ] perlexpr [ files ]

DESCRIPTION
       "rename" renames the filenames supplied according to the rule specified
       as the first argument.  The perlexpr argument is a Perl expression
       which is expected to modify the $_ string in Perl for at least some of
       the filenames specified.  If a given filename is not modified by the
       expression, it will not be renamed.  If no filenames are given on the
       command line, filenames will be read via standard input.

       For example, to rename all files matching "*.bak" to strip the
       extension, you might say

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


       To translate uppercase names to lower, you'd use


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


OPTIONS
       -v, --verbose
               Verbose: print names of files successfully renamed.

       -n, --no-act
               No Action: show what files would have been renamed.

       -f, --force
               Force: overwrite existing files.
-----------------------------------------------------------------------------------------------------------

參數 -v:會把更改成功的檔名顯示在螢幕上
參數 -n
參數 -f:假設有一樣檔名的檔案存在,會強制複寫檔案(小心使用)。


標示紅色的地方是重點,按照範例來看的話,我們要更改副檔名用的指令是
rename 's/原字元/新字元/' *.副檔名把指令改成我們想要的jpg變成gif

-----------------------------------------------------------------------------------------------------------
linux@linux:/$ rename 's/\.jpg$/\.gif/' *.jpg
linux@linux:/$ ls
a-01.gif  a-03.gif  a-05.gif  a-07.gif  a-09.gif
a-02.gif  a-04.gif  a-06.gif  a-08.gif  a-10.gif
-----------------------------------------------------------------------------------------------------------
更改完畢!

或許有人會會覺得奇怪,為什麼在.(點)的前面會多一個\的符號呢?
這是因為.(點)是屬於特殊字元,而\這個是屬於跳脫字元的符號,用途是在\後面的第一個字元都會變成普通字元,例如!' " |$%&* -()[ ] {}?+這些符號是有特殊意義的,一般使用的時候只要前面加一個\符號就會當成一般字元來看待。

還有為什麼.jpg的後面要一個$的符號呢,是$因為代表字尾的意思,假設檔名之中有.jpg才不會一起更改,因為這個範例更改的是副檔名,當然是以最後的為主。


除了更改副檔名之外,也可以改主檔名喔,例如a-01 ~ a-10.gif,我想改成ZZZ01.gif
-----------------------------------------------------------------------------------------------------------
linux@linux:/$ rename 's/a\-/ZZZ/' *.gif
linux@linux:/$ ls
ZZZ01.gif  ZZZ03.gif  ZZZ05.gif  ZZZ07.gif  ZZZ09.gif
ZZZ02.gif  ZZZ04.gif  ZZZ06.gif  ZZZ08.gif  ZZZ10.gif
-----------------------------------------------------------------------------------------------------------


rename還有另一個用途,可以把檔案名稱改成全部大寫或是全部小寫,例如我要全部改成大寫,那麼下的指令就是
-----------------------------------------------------------------------------------------------------------
linux@linux:/$ rename 'y/a-z/A-Z/' *
linux@linux:/$ ls
ZZZ01.GIF  ZZZ03.GIF  ZZZ05.GIF  ZZZ07.GIF  ZZZ09.GIF
ZZZ02.GIF  ZZZ04.GIF  ZZZ06.GIF  ZZZ08.GIF  ZZZ10.GIF
-----------------------------------------------------------------------------------------------------------



全部改成小寫,那麼下的指令就是
-----------------------------------------------------------------------------------------------------------
linux@linux:/$ rename 'y/A-Z/a-z/' *
linux@linux:/$ ls
zzz01.gif  zzz03.gif  zzz05.gif  zzz07.gif  zzz09.gif
zzz02.gif  zzz04.gif  zzz06.gif  zzz08.gif  zzz10.gif
-----------------------------------------------------------------------------------------------------------

2012年9月18日 星期二

Linux 檔案整理的 shell script

緣起:同一個目錄夾有許多avi +jpg(巷子內的應該知道我在說啥),每次都要手動更改檔名和移動到相對應的目錄夾,一個目錄可能就有數十個檔案,長期下來覺的自己很白痴,幹嘛不寫個shell script來執行就好。

功能:
1.建立和主檔名一樣的目錄夾,例如檔名是ABS-001.avi,那麼建立的目錄夾就會是ABS-001,大寫都會一樣喔!

2.會把相同檔名的所有檔案都移動到相對名稱的目錄夾,例如ABS-001.avi和ABS-001.jpg都會移動到ABS-001的目錄夾裡面。



步驟:

1.建立一個可執行的shell script
Linux@Linux:/$ touch createfolder.sh ; chmod +x createfolder.sh
Linux@Linux:/$ vi createfolder.sh

把紅字全部都複製貼上後儲存離開
-------------------------------------------------------------------------
#!/bin/bash
read -p "Please input subname : " subname
for i in *.$subname; do
if [ "$i" != "*.[$subname]" ]; then
filename="`echo $i | sed -e s/\.${subname}$//`"
mkdir ${filename}
mv ${filename}.* ${filename}
fi
done
-------------------------------------------------------------------------

2.接下來把剛剛新增好的createfolder.sh複製到/bin裡面,這是因為/bin是在$PATH的預設值內,放在這裡可以隨時執行。
Linux@Linux:/$ sudo cp createfolder.sh /bin


PS:目前這支shell script的缺點
1.需要自行輸入副檔名的名字,譬如avi或是jpg(大小寫有差別)。
2.主檔名要是大小寫不同,那建立的目錄夾也會不同,例如檔名是ABCDEF.avi和abcdef.jpg,那麼系統就會建立ABCDEF和abcdef兩個資料夾。