阿旺的 Linux 開竅手冊

 基礎篇    進階篇    補腦篇    指令索引  


HY-STAR's  Ads IWS's Ads


版權所有, 引用請註明出處

 基礎篇

Chapter 6 : 檔案操作/萬用字元

6.0 檔案基本操作
       連結檔
           符號連結
           硬連結
       ln 建立檔案連結
       cp 檔案複製
       rm 檔案刪除
       mv 檔案搬移
       〝\〞 跳脫字元
6.1 萬用字元
       rename 大量檔案更名





















檔案操作/萬用字元


6.0 檔案基本操作
檔案的基本操作不外乎複製、搬移、刪除、和重新命名等,但這些操作的檔案或目錄有時並非檔案本尊而是其〝分身〞;分身檔即所謂的〝連結檔〞(Linking files),所以有必要先了解〝連結檔〞。

連結檔
連結檔有點類似 Windows 的〝捷徑〞(Shortcut),但不完全相同 ,Windows 中的〝捷徑〞是一個實際會佔空間的檔案,副檔名為〝lnk〞。捷徑檔〝.lnk〞不直接記錄內容而是記錄某檔案的路徑,其目的是可大幅節省儲存空間。例如某一檔案或目錄有 100MB,但其捷徑檔〝lnk〞的大小應都小於 0.5K ,因捷徑檔〝lnk〞只記錄來源檔案的路徑和其他屬性(如是執行檔,其屬性可能還有執行時的啟動參數和啟動位置等內容)。

Linux 的檔案系統(Filesystem)標準為 ext2 ext3,其 filesystem 檔案的資訊記錄在 inode 而內容記錄在 block 內, 而連結檔可用 inode 來記錄來源檔的路徑不一定會動用到 block ,所以 Linux 的連結檔不一不定會像 Winodws 的〝捷徑〞一般會佔實際的空間。

Linux 的連結檔有兩種,一叫〝符號連結〞另一是〝硬連結〞,差別如下。 ln 建立檔案連結
知道了連結檔,來實際觀察和練習一下,建立檔案連結指令 ln (link)用法如下:

語法:ln [-otpiton][--option] source target_link_file
指令名稱/功能/命令使用者 選項 功能
ln/
(link)建立連結/
Any
-s 建立符號連結(Symbolic Link),如無此選項預設為硬連結 (Hard Link)
-b 如要建立的連結檔已存在,會先自動備份已存在的檔案(備份檔字尾加〝~〞)
-f 如要建立的連結檔已存在,覆蓋舊檔
--help 指令自帶說明


例: (符號連結)
$ ls -lgGh /etc/services ←查看一下檔案〝/etc/services〞的檔案大小
-rw-r--r-- 1 354K 2007-04-18 16:40 /etc/services ←檔案大小為 354K byte
$ ln -s /etc/services s_link ←建立符號連結檔〝s_link〞連結到〝/etc/services〞
$ ls -lgGh s_link ←查看一下符號連結檔〝s_link〞的大小
lrwxrwxrwx 1 13 2011-09-13 13:51 s_link -> /etc/services ←其符號連結只佔 13 byte

上例中.如讀或寫符號連結檔〝s_link〞就等於讀或寫來源檔〝/etc/services〞,但檔案大小比來源檔小多了只有 13 byte。如果細心點可能會發現到符號連結檔的大小剛好是〝路徑的字元數〞,所以符號連結檔事實上只記錄來源檔的路徑,所以 ln 如用相對路徑就可能會有延伸的問題,我們來實驗一下。

例:(符號連結檔相對/絕對路徑實驗)
$ cd ~ ←cd 到家目錄來實驗
$ echo '12345' > source ←建立一檔案〝source〞內容為〝12345〞
$ ln -sf source s_link ←建立符號連結檔〝s_link〞連結到工作目錄內的檔案〝source〞
$ cat s_link ←驗證一下軟連結檔〝s_link〞內容和〝source〞是否相同
12345
$ mv s_link /tmp ←實驗一下將軟連結檔〝s_link〞移到目錄 /tmp 下
$ cat /tmp/s_link ←驗證一下軟連結檔〝s_link〞內容
cat: /tmp/s_link: No such file or directory ←找不到檔案

$ ln -sf ~/source s_link ←用絕對路徑再實驗上述步驟
$ mv -f s_link /tmp
$ cat /tmp/s_link ←驗證一下
12345 ←如用絕對路徑,把軟連結檔移到其他目錄就不會有問題了
$ rm ~/source ←把來源檔殺掉
$ cat /tmp/s_link ←驗證一下來源檔不見了,軟連結檔會如何?
cat: /tmp/s_link: No such file or directory ←找不到檔案了

由以上的實驗可知操作符號連結最好用絕對路徑,且符號連結的來源檔如不小心被殺掉了,.就變無效連結。

符號連結的來源檔不只可連結檔案,目錄,甚至可跨越不同檔案系統哦。

例:(符號連結到目錄)
$ ln -s /etc s_link2dir ←建立符號連結檔〝s_link2dir〞連結到目錄〝/etc〞
$ ls -lgG s_link2dir ←用指令 ls 看一下〝s_link2dir〞有無連結到目錄〝/etc〞
lrwxrwxrwx 1 4 2011-09-13 16:49 s_link_dir -> /etc
$ cd s_link2dir ←看一下可不可以進入符號連結的目錄

實驗了符號連結(symbolic link),現在來實驗硬連結(hard link)。

例:
$ cp /etc/services /tmp ←複製 /etc/services 到 /tmp 目錄下準備作為實驗的來源檔
$ ln /tmp/services h_link ←建立硬連檔〝h_link〞硬連結到來源檔〝/tmp/services〞(ln 沒選項為硬連結)
$ ls -li /tmp/services h_link ←把兩個檔案列出看看
1880233 -rw-r--r-- 2 aaa aaa 362047 2011-09-13 17:09 h_link ←兩個檔案除檔名外都一樣
(上面故意用綠字 mark 為 inode 編號,紅字為 link 數)

1880233 -rw-r--r-- 2 aaa aaa 362047 2011-09-13 17:09 /tmp/services

$ rm /tmp/services ←把來源檔殺掉看看
$ ls -li h_link ←列出硬連結檔看看有無影響
1880233 -rw-r--r-- 1 aaa aaa 362047 2011-09-13 17:09 h_link ←來源檔殺掉了,不會影響硬連結檔(但 link 數變 1)
$ cat h_link ←驗證一下來源檔不見了,硬連結檔可否讀出?

一個檔案系統(以 Linux ext2/ext3 而言),不同的檔案其 inode 會有不同的編號,如果 inode 編號相同就是同一檔案。如果多一個硬連結,其 link 數會加一,如前所言硬連結檔既是本尊也是分身,所以只要其一沒被刪除,資料都安全的故安全性較佳,但命缺點為:不可連結目錄也不可跨越不同檔案系統。

cp 檔案複製
Linux 檔案複製指令 cp (copy),基礎用法很簡易,基本上為 cp 來源檔 目的檔 cp 來源檔案1 來源檔案n 目的路徑 (把一到多個檔案複製到目錄內)cp 來源目錄 目的目錄,進一步用法如下:

語法:cp [-otpiton][--option] source traget
指令名稱/功能/命令使用者 選項 功能
cp/
(copy)檔案複製/
Any
-a 完全複製(包含其檔案擁有者,連結,目錄,時間)同等 -dpR (常用於備份)
-b 如目的檔已存在會先自動備份已存在的檔案(備份檔字尾加〝~〞)
-d 如來源為符號連結檔,複製後的檔也為符號連結檔
-f 如複製的檔案已存在,不詢問直接覆蓋舊檔
-i 如複製的檔案已存在,覆蓋舊檔之前會要求詢問
-l 硬連結取代複製
-p 複製檔案時連其檔案擁有者,時間戳記,權限也一併複製
-r 遞回(recursive)複製,將來源目錄下所有的檔案及子目錄一併複製
-R 同 -r
-s 符號連結取代複製
-S字串 同 -b 但可指定備份檔字尾字串
-u 更新(只複製來源檔 mtime 時間比目的檔 mtime 時間新或目的地沒有的檔案)
-v 顯示複製過程
--help 指令自帶說明

例:
$ cp file1 file2 ←將 file1 複製到 file2
$ cp /dev/null file1 ←將 file1 內容清空
$ cp /dir/file ./ ←將檔案 /dir/file 複製到工作目錄
$ cp file ../ ←將工作目錄的檔案複製到其父目錄
$ cp -r dir1/ dir2/ ←將來源目錄 dir1 下所有的檔案及子目錄一併複製到目錄 dir2 內
$ cp file1 file2 file3 dir ←如果來源檔不只一個,目的一定要為目錄,此例為將 file1~file3 複製到目錄 dir 內
$ cp -b /dir/file ./ ←如果工作目錄 file 已存在,file 會先備份為 file~ 再進行複製的動作
$ cp -S'_backuped' file1 file2 ←如果 file2 已存在,file2 會先備份為 file2_backuped 再進行複製的動作(指定備份檔字尾字串)
$ cp -auv dir1/ dir2/ ←更新目錄 dir2 (來源為 dir1)且顯示更新的過程(此例時常用於備份)
$ cp -s file1 file2 ←同等於指令 ln -s file1 file2,建立符號連結檔 file2
$ cp -l file1 file2 ←同等於指令 ln file1 file2, 建立硬連結
$ cp -i file1 file2 ←將 file1 複製為 file2 但如 file2 已存在,覆蓋舊檔之前會要求詢問

Linux 的 cp 指令有一特色,即如果權限許可,不管來源檔擁有者群組屬誰,複製過來的檔案的擁有者和群組會變操作者所有,當然其用意是讓操作者可以完全操控複製過來的檔案.如要維持原屬性,就要用 cp -acp -p

例:
$ ls -l /etc/fstab ←查看 /etc/fstab 的擁有者和群組
-rw-r--r-- 1 root root 608 2011-09-16 00:21 /etc/fstab ←擁有者,群組,兩者目前都屬〝root〞所有
$ cp /etc/fstab ./ ←複製 /etc/fstab 到工作目錄
$ ls -l fstab ←查看工作目錄檔案 fstab 的擁有者和群組
-rw-r--r-- 1 aaa aaa 608 2012-02-10 12:50 fstab ←擁有者/群組變建立者所有

上例中就算加選項 cp -p 也無法把擁有者和群組〝root〞複製過來,因其權限不足。反之如用 root 登入操作 cp -p ,因權限無限大就可把完全複製任何的擁有者和群組。

另外複製指令 cp 如來源為檔為符號連結檔,目的檔將不再是符號連結檔(而是直接複製其目的檔),如要保留目的檔也為符號連結檔就用選項 cp -d,而 cp -a 等於 cp -d -p -R 三個選項加起來的功能,即完全複製,時常用來備份檔案。

如果用 cp 於日常的備份,但檔案很大又很多,每個檔案都複製常浪費許多時間,用選項〝-u〞可節省許多的時間。因可根據 mtime 時間來判斷檔案有無更新,或有無新的檔案來判斷是否要複製。

另外建議養成好的指令操作習慣,如操作的為目錄,目錄的字尾最好加〝/〞以區別是目錄。例如將目錄 dir1 複製到目錄 dir2, 寫成 cp -r dir1 dir2 即可,但用 cp -r dir1/ dir2/ 更清楚明白操作的為目錄。事實上目錄的標準寫法後面是要加〝/〞只是大部分的人都省略,但有些應用,目錄後面非加〝/〞不可;如 ls -d */ 為列出工作目錄內還有那些目錄但不列出檔案。

rm 檔案刪除
Linux 刪除檔案指令 rm (remove),基本用法為 rm 檔案1 檔案n, 進階用法如下:

語法:cp [-otpiton][--option] file/directory
指令名稱/功能/命令使用者 選項 功能
rm/
(remove)刪除檔案/
Any
-f 不詢問直接刪除檔案
-i 刪除檔案之前會要求詢問
-r 遞回(recursive)刪除,將來源目錄下所有的檔案及子目錄一併刪除
-R 同 -r
-v 顯示刪除過程
--help 指令自帶說明

rm 刪除檔案指令也可刪除目錄,如用 rm -fr dir/ 來刪除目錄連問都不問就把整個目錄都殺光。所以 rm 是很危險的指令,所以建議殺目錄用專屬的殺目錄指令 rmdir 比較安全。

例:
$ rm file ←刪除檔案 file
$ rm 'file 1' ←刪除檔案〝file 1〞(如檔名有空格要用引號括起來)
$ rm file1 file2 file3 ←刪除檔案可連殺
$ rm -ri dir/ ←刪除目錄和目錄內的所有檔案,並要求每個檔案詢問
$ rm -rf dir ←不詢問直接刪除目錄和目錄內的所有檔案
$ rm ./-10degree ←刪除檔案〝-10degree〞

最後一個例子比較要注意一下,如檔案的第一個字用比較奇怪的字元,如例子中的檔案〝-10degree〞,但〝-〞又會被誤判為選項,所以要用代表工作目錄的〝./〞來隔開,但還是不太建議檔名太標新立異。

mv 檔案搬移
檔案搬移指令 mv (move) 和檔案複製指令 cp 用法和選項和都很類似,差別只是檔案搬移 mv 會把來源的檔案殺掉。且 mv 沒有〝-r〞或〝-R〞目錄遞回的選項,因如 mv 用於搬移目錄,已包含目錄內的檔案和子目錄一起搬移,mv 用法如下。

語法:mv [-otpiton][--option] source target
指令名稱/功能/命令使用者 選項 功能
mv/
(move)檔案搬移/
Any
-b 如目的檔案已存在,會先自動備份已存在的檔案(備份檔字尾加〝~〞)
-f 如目的檔案已存在,不詢問直接覆蓋舊檔
-i 如目的檔案已存在,覆蓋舊檔之前會要求詢問
-S字串 同 -b 但可指定備份檔字尾字串
-u 只搬移更新檔(只搬移來源檔 mtime 時間比目的檔 mtime 時間新或目的地沒有的檔案)
-v 顯示搬移過程
--help 指令自帶說明

例:
$ mv file1 file2 ←將 file1 搬移到 file2,此例同等於將 file1 更名為 file2
$ mv dir1/ dir2/ ←將目錄 dir1(包含 dir1 內所有的檔案和子目錄)搬移到 dir2,此例同等於目錄更名
$ mv -i file ../ ←將 file1 搬移到其父目錄,如目地檔存在並要求詢問
$ mv -b file dir/ ←將 file1 搬移到目錄 dir,如目地檔存在,覆蓋之前先備份(備份檔字尾加〝~〞)

第一個例子 mv file1 file2 也是 mv 主要的用法之一,用於更名。

〝\〞 跳脫字元
跳脫字元〝\〞(escape characters)用意為因語法衝突,故不得已暫時脫離某特殊字元(、/、"、{、? 等)原預設的功能或轉變功能,例如想在螢幕顯示〝I'm happy and I'm a student〞用 echo 指令寫成 echo I'm happy and I'm a student 會引起錯誤的輸出,因單引號〝'〞或雙引號〝'〞是括入字串的意思,故如要正確的輸出可加跳脫字元〝\〞使暫時脫離引號原有的功能而寫成 echo I\'m happy and I\'m a student

例:(暫時脫離某特殊字元原預設的功能)
$ echo > "fileA" ←製造個檔案〝 "fileA" 〞
$ echo > ""fileB"" ←製造個檔案〝 ""fileB"" 〞
$ ls ←確認一下
fileA      fileB ←檔案的引號不見了?
$ echo > \"fileC\" ←加跳脫字元再製造個檔案〝 "fileC" 〞看看
$ ls
fileA      fileB      "fileC" ←〝fileC〞有引號吔

$ rm \"fileC\" ←加跳脫字元才可操作語法衝突的檔案


例:(轉變功能)
echo -e 'I\x27m a student' ←加跳脫字元使轉變功能為 ASCII 碼(ASCII 碼 27HEX為單引號)
I'm a student

\ls  ←指令之前加跳脫字元代表〝除去別名〞,(ls 輸出就不會五顏六色)


^ back on top ^




6.1 萬用字元

萬用字元(Wildcard characters)和管線重定向是 Linux 指令的三大`神通,可讓文字界面的威力由砲彈昇華為核彈,是圖形操作界面難以望其項背。

萬用字元主要的目的是在匹配檔名,萬用字元中的〝字元〞(Character)是以 ASCII code 所定義的英文字母或數字或符號稱為一個字元,例如英文字母〝A〞(ASCII=65)為一個字元。 一個以上的字元可組成一字串(String),例如〝XYZ〞為一字串。

傳統的檔名皆以 ASCII code 來編碼,所以善用萬用字元可減化檔案的操作,因 Linux shell 本身就能解讀萬用字元,故幾乎任何和檔案有關的指令皆可配合萬用字元,檔名有用到萬用字元來匹配叫〝globbing patterns〞或簡稱〝glob〞,常用的用法如下:
萬用字元雖好用,但也有其肓點時常困惑使用者,那就就遇到隱藏檔(〝.〞開頭的檔案)常會無效。舉例來說〝/tmp〞目錄內可能有許多的隱藏檔,但我想把此目錄內的檔案和目錄都清空,用 rm -fr * 郤無法把隱藏檔刪除。最主要原因為〝*〞代表任何東西,所以代表 rm -fr * 連同代表其目錄本身的〝.〞和其上層目錄的〝..〞也一起刪除,但這應不是我們期望的,所以只好放過〝.〞開頭的檔案。

當然其他指令如 ls *cp * ~/ 也會遇到類似的問題,解決辦法之一為用〝.[^.]*〞來匹配以〝.〞開頭的隱藏檔但又可排除〝.〞和〝..〞,如 rm -fr .[^.]* 表示刪除工作目錄中所有的隱藏檔。

另外非常不建議用很奇怪的檔名,如檔案開頭為〝-〞或檔名中有〝#、@、%、\、?、|、{、}〞等奇怪的字元,因有可能會讓萬用字元失效(試過許多的 Linux 發行版都有此 issue)或很不容易篩選和四配所要的檔案,我們來實驗一下吧!

實驗:
$ echo > abc ←製造一長度為三個字元的檔案
$ ls ??? ←驗證一下
abc
$ echo > -12 ←製造一檔案〝-12〞(長度也為三個字元)
$ ls ??? ←再驗證一下
ls: invalid option -- 2 ←??? 失效了
Try `ls --help' for more information.
$ ls * ←列出所有檔案
ls: invalid option -- 2 ←靈異事件 ? 萬用字元全失效
$ rm -f ./-12 ←把這靈異檔案殺掉吧
$ ls ??? ←再驗證一下
abc ←正常了 :-)

rename 大量檔案更名
rename 用法很另類主要是對付一堆的檔案,而語法也特立獨行,一定要有萬用字元的樣板。

其語法為 rename OLD_NAME  NEW_NANE  PATTERN ,其中 PATTERN 為萬用字元的樣板,只要符合萬用字元的樣板就用 NEW_NANE 取代 OLD_NAME。

用實例來操作就很容易明白用法。例如我在基隆拍了 50 張的照片,但相機的預設檔名是 IMAGE0001.jpg ~ IMAGE0050.jpg ,但這種傻瓜檔名時間一久我就忘了是在那拍的照片,所以想把全部檔名改為拍攝地點的 keelung0001.jpg ~ keelung0050.jpg 。而用 mv 指令或用 Windows 的 GUI 一一改檔名操作,保證會操作到抽筋,用 rename 就方便多了。

例:(假設工作目錄內已有 IMAGE0001.jpg~IMAGE0050.jpg 共 50 個檔案)
$ rename IMAGE keelung IMAGE* ←把檔案 IMAGE0001.jpg ~ IMAGE0050.jpg 全改檔名為
keelung0001.jpg ~ keelung0050.jpg


例:(續上例,工作目錄內已有 IMAGE0001~IMAGE0050 共 50 個檔案)
$ rename IMAGE00 keelung00 IMAGE00[0-2]?.* ←把檔案 IMAGE0001.jpg ~IMAGE0029.jpg
全改檔名為 keelung0001.jpg~keelung0029.jpg,其餘不改

例:
$ rename .config .cfg *.config ←把所有工作目錄中,副檔名為〝.config〞改為〝.cfg〞
$ rename - _ *-* ←把所有檔案中檔名中的減號〝-〞改為底線〝_〞

不只是檔案, rename 也可用在大量更名目錄,其實頂好用的!
例:(假設家目錄內已有目錄 catlog00~catlog99,共 100 個目錄)
$ rename ~/catlog ~/list ~/catlog?? ←把家目錄內的目錄 catlog00~catlog99 全改目錄名為 list00~list99

當然只要高興,用牛刀殺雞也沒什麼不可,rename 也可用來重新更名單一檔案。

例:
$ rename abc wxyz * ←把〝abc〞更名為〝wxyz〞


^ back on top ^
















[註6.0]參考 http://www.farhadsaberi.com/linux_freebsd/2010/12/hard-link-soft-symbolic-links.html

[註6.1]可用 LANG= 來設定語系,如下例:
$ LANG= ←清除所有設定的語系(同等〝LANG=C〞或〝LANG=POSIX〞為清除所有設定的語系)
$ LANG=en_US.UTF-8 ←設定語系為〝en_US.UTF-8〞