bash之參數擴展(Parameter Expansion)

寫在前面

如果你問我bash的這麼多擴展哪個功能最強大,那我會毫不猶豫地告訴你,當然是參數擴展啦~

爲什麼說參數擴展功能強大呢?那是因爲通過參數擴展功能,我們可以完成很多意想不到的功能,例如可以完成參數值的刪除、截取以及替換等功能~

 

SHELL參數以及參數的分類

開始講述參數擴展之前,我們先要了解什麼是shell的參數,以及引用參數的不同方法。

其實在shell編程中,參數(parameter)是個大概念,也是個籠統的概念,在bash手冊中對參數的定義只是一句話:

A parameter is an entity that stores values. 

意思是說在shell中參數是個實體(entity),這個實體中存儲着各式各樣的值(values)。

緊接着提到:

It can be a name, a number, or one of the special characters listed below under Special Parameters.

這句話其實是告訴我們,可以通過三類方式來引用參數,從而得到參數中存儲的值。根據引用方式的不同,可以將參數分爲三類,歸納如下:

(1)通過名稱(name)來引用參數,這樣的參數我們稱之爲變量(variables )。一個變量擁有自己的值和諸多屬性,屬性可以通過declare來設定,可以通過unset來取消一個變量。

(2)通過數字(number)來引用參數,這樣的參數我們稱之爲位置參數(Positional Parameters)。位置參數在腳本被調用時自動初始化爲傳遞給腳本的參數。腳本中調用函數時,位置參數會暫時替換成傳遞給函數的參數。我們可以使用set命令來改變位置參數的值,但是不能試圖通過賦值語句來改變位置參數的值。(參考《Handling positional parameters》)

(3)最後還有一類參數,被稱之爲特殊參數(Special Parameters)。特殊在哪裏? 特殊在我們只能通過shell內部預定義的特殊符號來引用它們,並且我們只能引用,不能試圖通過賦值語句來重新賦值。預定義的特殊符號包括:*  @  $  ?  !  -  $  0  (參考《Special parameters and shell variables》)

(參考鏈接:《Parameter》《Parameters》)

 

什麼是參數擴展呢?

講白了,所謂參數擴展就是通過符號$獲得參數中存儲的值。只不過呢,在獲得最終的結果之前,允許我們對參數以及參數值做很多操作,例如本文一開始就提到的對參數值進行刪除、截取以及替換等操作~

本篇博文就是詳細討論參數擴展過程中我們可以進行的諸多操作。

 

最簡單的形式

參數擴展最簡單直接的形式如下:

$parameter

或者

${parameter}

個人傾向於後者,第一有花括號一看就知道是參數擴展,其次可以根據需要在右花括號後頭追加字符(串),否則shell會認爲是參數的一部分。舉個小例子就知道了,如下:

[09:49:23@astrol:~]$ WORD=car
[09:49:25@astrol:~]$ echo "The plural of $WORD is most likely $WORDs"
The plural of car is most likely
[09:49:27@astrol:~]$ echo "The plural of $WORD is most likely ${WORD}s"
The plural of car is most likely cars

可以看到不加花括號的話,shell認爲WORDs是參數,然而我們並沒有設置過這個參數,因此擴展結果爲空。

需要注意的是,在bash中引用位置參數時,大於第9個參數時,兩位的數字要求必須要在花括號內。例如:${10}

另外,後文介紹的各種操作都是需要在花括號內進行的。

 

使用默認值(Use Default Values)

test

 

賦值默認值(Assign Default Values)

test

 

間接擴展(indirect expansion)

間接擴展也被很多人稱爲間接引用。如果熟悉C/C++的話,可以簡單的把間接擴展理解成指針變量。

 

 

 

子串擴展(Substring Expansion)

${parameter:offset}

${parameter:offset:length}

子串擴展的意思是從offset位置開始截取長度爲length的子串,如果沒有提供length,則是從offset開始到結尾。需要注意的幾點是:

(1)如果offset是個負值,開始位置是從字符串末尾開始算起,然後取長度爲length的子串。例如,-1代表是從最後一個字符開始。

(2)如果length是個負值,那麼length的含義不再代表字符串長度,而是代表另一個offset,位置從字符串末尾開始,擴展的結果是offset ~ length之間的子串。

(3)如果parameter是@,也就是所有的位置參數時,offset必須從1開始。

來看幾個例子:

[17:58:36@astrol:~]$ MYSTRING="Be liberal in what you accept, and conservative in what you send"
[17:59:19@astrol:~]$ echo ${MYSTRING}
Be liberal in what you accept, and conservative in what you send
[17:59:30@astrol:~]$ echo ${MYSTRING:34}
conservative in what you send
[17:59:42@astrol:~]$ echo ${MYSTRING:34:13}
conservative
[17:59:56@astrol:~]$ echo ${MYSTRING: -10:5}
t you
[18:00:18@astrol:~]$ echo ${MYSTRING:(-10):5}
t you
[18:00:23@astrol:~]$ echo ${MYSTRING:11:-17}
in what you accept, and conservative

可以看到當offset是負值時,負號(-)必須與冒號(:)有間隔,這是爲了避免與上文提到的${parameter:-word} 混淆。

 

查找和替換(Pattern  substitution)

${parameter/pattern/string}

${parameter//pattern/string}

${parameter/pattern}

${parameter//pattern}

pattern和路徑擴展(pathname expansion)中的模式匹配(pattern matching)一樣(詳情可參考文章《bash之通配符》),匹配後的子串會用string替換掉。需要注意的有以下幾點:

(1)parameter之後如果是/,則只替換匹配到的第一個子串;parameter之後如果是//,則替換所有匹配到的子串。

(2)當string爲空時,則相當於將匹配的子串刪除。

(3)特殊符號#%在這種情況下分別錨定(Anchoring )字符串的開始和結尾。

(4)如果bash的nocasematch選項參數是打開的(shopt -s nocasematch),則匹配的過程大小寫是不敏感的。

例子如下:

[19:26:39@astrol:~]$ MYSTRING="Be liberal in what you accept, and conservative in what you send"
[19:26:40@astrol:~]$ echo ${MYSTRING}
Be liberal in what you accept, and conservative in what you send
[19:26:46@astrol:~]$ echo ${MYSTRING//conservative/happy}
Be liberal in what you accept, and happy in what you send
[19:27:04@astrol:~]$ echo ${MYSTRING/in/by}
Be liberal by what you accept, and conservative in what you send
[19:27:21@astrol:~]$ echo ${MYSTRING//in/by}
Be liberal by what you accept, and conservative by what you send
[19:27:24@astrol:~]$ echo ${MYSTRING/conservative/}
Be liberal in what you accept, and in what you send
[19:27:50@astrol:~]$ MYSTRING=xxxxxxxxxxxxxxx
[19:28:09@astrol:~]$ echo ${MYSTRING}
xxxxxxxxxxxxxxx
[19:28:17@astrol:~]$ echo ${MYSTRING/#x/y}
yxxxxxxxxxxxxxx
[19:28:26@astrol:~]$ echo ${MYSTRING/%x/y}
xxxxxxxxxxxxxxy

bash的這個查找替換功能跟sed的很像,不同的是這裏的pattern不是正則表達式。

 

查找並刪除(Remove matching prefix/suffix pattern)

${parameter#pattern}

${parameter##pattern}

${parameter%pattern}

${parameter%%pattern}

刪除匹配到的子串。直接來看例子吧,假設我們定義了一個變量爲:

file=/dir1/dir2/dir3/my.file.txt

那麼:

${file#*/}:刪除第一個 / 及其左邊的字符串:dir1/dir2/dir3/my.file.txt 
${file##*/}:刪除最後一個 / 及其左邊的字符串:my.file.txt , 相當於basename ${file}
${file#*.}:刪除第一個 . 及其左邊的字符串:file.txt 
${file##*.}:刪除最後一個 . 及其左邊的字符串:txt  
${file%/*}:刪除最後一個 / 及其右邊的字符串:/dir1/dir2/dir3,相當於dirname ${file}
${file%%/*}:刪除第一個 / 及其右邊的字符串:(空值) 
${file%.*}:刪除最後一個 . 及其右邊的字符串:/dir1/dir2/dir3/my.file 
${file%%.*}:刪除第一個 . 及其右邊的字符串:/dir1/dir2/dir3/my

記憶的方法爲:
# 是去掉左邊(在鍵盤上 # 在 $ 之左邊) 
% 是去掉右邊(在鍵盤上 % 在 $ 之右邊) 
單一符號是最小匹配﹔兩個符號是最大匹配。

 

獲取參數值長度(Parameter  length)

${#parameter}

這個擴展很簡單,就是返回parameter值的長度值。

[20:49:27@astrol:~]$ MYSTRING="Be liberal in what you accept, and conservative in what you send"
[20:49:27@astrol:~]$ echo ${MYSTRING}
Be liberal in what you accept, and conservative in what you send
[20:49:34@astrol:~]$ echo ${#MYSTRING}
64

 

大小寫轉換(Case modification)

${parameter^}

${parameter^^}

${parameter,}

${parameter,,}

字符^意思是將第一個字符轉換成大寫字母,^^的意思是將所有的字符轉換成大寫字母。

字符,意思是將第一個字符轉換成小寫字母,,,的意思是將所有的字符轉換成小寫字母。

來看如下例子:

[20:00:49@astrol:~]$ lower="lowercase letters"
[20:00:55@astrol:~]$ echo ${lower}
lowercase letters
[20:01:08@astrol:~]$ echo ${lower^}
Lowercase letters
[20:01:12@astrol:~]$ echo ${lower^^}
LOWERCASE LETTERS
[20:01:15@astrol:~]$ echo ${lower} | tr '[:lower:]' '[:upper:]'
LOWERCASE LETTERS
[20:01:43@astrol:~]$
[20:01:49@astrol:~]$ UPPER="UPPER LETTERS"
[20:02:01@astrol:~]$ echo ${UPPER}
UPPER LETTERS
[20:02:07@astrol:~]$ echo ${UPPER,}
uPPER LETTERS
[20:02:09@astrol:~]$ echo ${UPPER,,}
upper letters
[20:02:11@astrol:~]$ echo ${UPPER} | tr '[:upper:]' '[:lower:]'
upper letters

關於大小寫轉換的更多例子可以參考《Shell Script: Convert Lowercase to Uppercase

 

參考鏈接:

 

BASH: Parameter expansion》(需梯子)

shell變量詳解

Linux 技巧: Bash 參數和參數擴展》《Bash parameters and parameter expansions

Shell參數擴展

Linux Shell參數擴展(Parameter Expansion)

Bash parameters and parameter expansions

An introduction to parameter expansion in Bash

第三十五章 : 字符串和數字》(shell百科

Bash String Processing

How-To: Bash Parameter Expansion and Default Values

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章