截取文件名和后綴
編寫Shell腳本的過程中,經常會和文件名和文件路徑打交道。如果用戶輸入了一個文件的全名(可能包含絕對路徑和文件后綴),如何得到文件的路徑名,文件名,文件后綴這些信息呢。Shell腳本擁有強大的字符串處理能力,如果把文件名當做字符串,我們不難使用cut或sed這樣的工具得到我們想要的結果。
|
|
這里使用basename命令可以直接得到包含后綴的文件名,而dirname命令可以得到路徑名,然后就能簡單的用cut截取文件名和后綴名。
更復雜的情況
如果對付簡單應用場景,到這里已經可以打完收工了,但是有時候文件可能不止有一個后綴,比如*.tar.gz,怎樣得到最后一個后綴呢?再cut一回?當然可以,但是如果文件名是mylib.1.0.1a.zip這樣的呢?呃……正則表達式肯定可以。
|
|
這里面的邏輯是這樣的:
- 文件名:把以
.字符開頭以后一直到行尾都是非.字符的子串替換為空。 - 后綴名:把從行首開始以
.字符結尾的子串替換為空。
光用語言把這兩個正則表達式描述出來腦細胞也要死不少。有沒有像上面cut版本一樣簡單容易理解的方法呢?由於.分隔符的個數不確定,正常使用cut來分割最后一個.字符是不太可能的。但是我們可使用 rev 命令將字符串反轉一下,區分后綴和文件名的.字符位置就確定了。截取了想要的部分之后,再次反轉就得到了我們想要的內容。
|
|
使用參數擴展
其實不借助復雜的正則表達式,甚至不調用basename, dirname, cut, sed命令,shell腳本一樣可以做到所有的操作。看下面的實現:
|
|
真是不能再簡潔了,大括號之內變量名配合幾個神奇的字符,就是Shell的參數擴展(Parameter Extension)功能。
${fullfile##*/}:從前面開始刪除fullfile中最大匹配(longest matching pattern)*/的字符串${fullfile%/*}:從后面開始刪除fullfile中最小匹配(shortest matching pattern)/*的字符串${fullname##*.}:從前面開始刪除fullname中最大匹配(longest matching pattern)*.的字符串${fullname%.*}:從后面開始刪除fullname中最小匹配(shortest matching pattern).*的字符串
參數擴展有多種形式,在shell編程中可以用作參數的拼接,字符串的替換,參數列表截取,變量初值等操作,這里不再詳述,請參考后面的功能列表和官方文檔
參數擴展功能列表
| 參數形式 | 擴展后 |
|---|---|
| x{y,z} | xy xz |
| ${x}{y, z} | ${x}y ${x}z |
| ${x}{y, $z} | ${x}y ${x}${z} |
| ${param#pattern} | 從param前面刪除pattern的最小匹配 |
| ${param##pattern} | 從param前面刪除pattern的最大匹配 |
| ${param%pattern} | 從param后面刪除pattern的最小匹配 |
| ${param%%pattern} | 從param后面刪除pattern的最大匹配 |
| ${param/pattern/string} | 從param中用string替換pattern的第一次匹配,string可為空 |
| ${param//pattern/string} | 從param中用string替換pattern的所有匹配,string可為空 |
| ${param:3:2} | 截取$param中索引3開始的2個字符 |
| ${param:3} | 截取$param中索引3至末尾的字符 |
| ${@:3:2} | 截取參數列表$@中第3個開始的2個參數 |
| ${param:-word} | 若$param為空或未設置,則參數式返回word,$param不變 |
| ${param:+word} | 若$param為非空,則參數式返回word,$param不變 |
| ${param:=word} | 若$param為空或為設置,則參數式返回word,同時$param設置為word |
| ${param:?message} | 若$param為空或為設置,則輸出錯誤信息message,若包含空白符,則需引號 |
