Shell腳本編程(二):shell變量

定義變量

定義變量時,變量名不加美圓符號($,PHP語言中變量須要),如:shell

your_name="runoob.com"

注意,變量名和等號之間不能有空格,這可能和你熟悉的全部編程語言都不同。同時,變量名的命名須遵循以下規則:編程

  • 命名只能使用英文字母,數字和下劃線,首個字符不能以數字開頭。
  • 中間不能有空格,可使用下劃線(_)。
  • 不能使用標點符號。
  • 不能使用bash裏的關鍵字(可用help命令查看保留關鍵字)。

有效的 Shell 變量名示例以下:數組

DEVICENAME
LD_LIBRARY_PATH
_var
var2

無效的變量命名:bash

?devicetype=123
user name=runoob
status = 0
7isactive=1

除了顯式地直接賦值,還能夠用語句給變量賦值,如:服務器

for file in `ls /etc`
或
for file in $(ls /etc)

以上語句將 /etc 下目錄的文件名循環出來。編程語言

使用變量

使用一個定義過的變量,只要在變量名前面加美圓符號便可,如:函數

#!/bin/bash
devicetype='lift'
echo $devicetype

變量名外面的花括號是可選的,加不加都行,加花括號是爲了幫助解釋器識別變量的邊界,好比下面這種狀況:post

for skill in Ada Coffe Action Java; do
    echo "I am good at ${skill}Script"
done

若是不給skill變量加花括號,寫成echo "I am good at $skillScript",解釋器就會把$skillScript當成一個變量(其值爲空),代碼執行結果就不是咱們指望的樣子了。this

推薦給全部變量加上花括號,這是個好的編程習慣url

已定義的變量,能夠被從新定義,如:

#!/bin/bash
devicetype='lift'
echo $devicetype
devicetype='crane'
echo $devicetype

結果

lift
crane

這樣寫是合法的,但注意,第二次賦值的時候不能寫$your_name="alibaba",使用變量的時候才加美圓符($)。

只讀變量

使用 readonly 命令能夠將變量定義爲只讀變量,只讀變量的值不能被改變。

下面的例子嘗試更改只讀變量,結果報錯:

#!/bin/bash
pdfurl='http://www.xxxx.com/resource/pdfs/181101/6238258284.pdf'
echo $pdfurl
readonly pdfurl
pdfurl='http://www.xxxx.com/resource/pdfs/181111/6238258255.pdf'
echo $pdfurl

運行腳本,能夠看到第二次賦值沒有成功,而且報錯,結果以下:

http://www.xxxx.com/resource/pdfs/181101/6238258284.pdf
http://www.xxxx.com/resource/pdfs/181101/6238258284.pdf
/tmp/922461712/main.sh: line 5: pdfurl: readonly variable

刪除變量

使用 unset 命令能夠刪除變量。語法:

unset variable_name

變量被刪除後不能再次使用。unset 命令不能刪除只讀變量。

實例

#!/bin/bash
# 定義兩個變量並打印
pdfurl='http://www.xxxx.com/resource/pdfs/181101/6238258284.pdf'
imgurl='http://www.xxxx.com/resource/imgs/181101/6238258284.jpg'
echo $pdfurl
echo $imgurl
# 將pdfurl置爲只讀
readonly pdfurl
# 嘗試刪除這兩個變量
unset pdfurl
unset imgurl
# 再次打印
echo $pdfurl
echo $imgurl

執行實例,能夠看到第二次只打印了imgurl。

http://www.xxxx.com/resource/pdfs/181101/6238258284.pdf
http://www.xxxx.com/resource/imgs/181101/6238258284.jpg
http://www.xxxx.com/resource/pdfs/181101/6238258284.pdf

/tmp/219033109/main.sh: line 10: unset: pdfurl: cannot unset: readonly variable

變量做用域

Shell變量的做用域(Scope),就是 Shell 變量的有效範圍(可使用的範圍)。

在不一樣的做用域中,同名的變量不會相互干涉,就好像 A 班有個叫小明的同窗,B 班也有個叫小明的同窗,雖然他們都叫小明(對應於變量名),可是因爲所在的班級(對應於做用域)不一樣,因此不會形成混亂。可是若是同一個班級中有兩個叫小明的同窗,就必須用相似於「大小明」、「小小明」這樣的命名來區分他們。

Shell 變量的做用域能夠分爲三種:

  • 有的變量能夠在當前 Shell 會話中使用,這叫作全局變量(global variable)
  • 有的變量只能在函數內部使用,這叫作局部變量(local variable)
  • 而有的變量還能夠在其它 Shell 中使用,這叫作環境變量(environment variable)

1.全局變量

所謂全局變量,就是指變量在當前的整個 Shell 會話中都有效。每一個 Shell 會話都有本身的做用域,彼此之間互不影響。在 Shell 中定義的變量,默認就是全局變量。

想要實際演示全局變量在不一樣 Shell 會話中的互不相關性,可在圖形界面下同時打開兩個 Shell,或使用兩個終端遠程鏈接到服務器(SSH)。

首先打開一個 Shell 窗口,定義一個變量 a 並賦值爲 1,而後打印,這時在同一個 Shell 窗口中是可正確打印變量 a 的值的。而後再打開一個新的 Shell 窗口,一樣打印變量 a 的值,但結果卻爲空,如圖 所示。

打開兩個Shell會話

這說明全局變量 a 僅僅在定義它的第一個 Shell 中有效,對其它 Shell 沒有影響。這很好理解,就像小王家和小徐家都有一部電視機(變量名相同),可是同一時刻小王家和小徐家的電視中播放的節目能夠是不一樣的(變量值不一樣)。

須要強調的是,全局變量的做用範圍是當前的 Shell 會話,而不是當前的 Shell 腳本文件,它們是不一樣的概念。打開一個 Shell 窗口就建立了一個 Shell 會話,打開多個 Shell 窗口就建立了多個 Shell 會話,每一個 Shell 會話都是獨立的進程,擁有不一樣的進程 ID。在一個 Shell 會話中,能夠執行多個 Shell 腳本文件,此時全局變量在這些腳本文件中都有效。

例如,如今有兩個 Shell 腳本文件,分別是 a.sh 和 b.sh。a.sh 的代碼以下:

#!/bin/bash
echo $a
b=200
b.sh 的代碼以下:
#!/bin/bash

echo $b
打開一個 Shell 窗口,輸入如下命令:
$ a=99
$ . ./a.sh
99
$ . b.sh
200
$
從輸出結果能夠發現,在 Shell 會話中以命令行的形式定義的變量 a,在 a.sh 中有效;在 a.sh 中定義的變量 b,在 b.sh 中也有效。

2.局部變量

Shell 也支持自定義函數,可是 Shell 函數和 C/C++、Java 等其餘編程語言函數的一個不一樣點就是:在 Shell 函數中定義的變量默認也是全局變量,它和在函數外部定義變量擁有同樣的效果。請看下面的代碼:
#!/bin/bash
#定義函數
function func(){
a=99
}
#調用函數
func
#輸出函數內部的變量
echo $a
輸出結果:
99

a 是在函數內部定義的,可是在函數外部也能夠獲得它的值,證實它的做用域是全局的,而不是僅限於函數內部。

要想變量的做用域僅限於函數內部,那麼能夠在定義時加上命令,此時該變量就成了局部變量。請看下面的代碼:
local
#!/bin/bash
#定義函數
function func(){
local a=99
}
#調用函數
func
#輸出函數內部的變量
echo $a
輸出結果爲空,代表變量 a 在函數外部無效,是一個局部變量。
Shell 變量的這個特性和 JavaScript 中的變量是相似的。在 JavaScript 函數內部定義的變量,默認也是全局變量,只有加上關鍵字,它纔會變成局部變量。
var

3.環境變量

全局變量只在當前 Shell 會話中有效,若是使用命令將它導出,那麼它就在全部的子 Shell 中也有效了,這稱爲「環境變量」。

環境變量被建立時所處的 Shell 被稱爲父 Shell,若是在父 Shell 中再建立一個 Shell,則該 Shell 被稱做子 Shell。當子 Shell 產生時,它會繼承父 Shell 的環境變量爲本身所用,因此說環境變量可從父 Shell 傳給子 Shell。不難理解,環境變量還能夠傳遞給孫 Shell。
export

注意,環境變量只能向下傳遞而不能向上傳遞,即「傳子不傳父」。

在一個 Shell 中建立子 Shell 最簡單的方式是運行 bash 命令,如圖所示。
進入子 Shell
經過命令能夠一層一層地退出 Shell。
下面演示一下環境變量的使用:
exit
$ a=22      #定義一個全局變量
$ echo $a    #在當前Shell中輸出a,成功
22
$ bash    #進入子Shell
$ echo $a    #在子Shell中輸出a,失敗

$ exit    #退出子Shell
exit
$ export a    #將a導出爲環境變量
$ bash    #從新進入子Shell
$ echo $a    #在子Shell中再次輸出a,成功
22
$ exit    #退出子Shell
exit
$ exit    #退出父Shell,結束整個Shell會話
能夠發現,默認狀況下,a 在子 Shell 中是無效的;使用 export 將 a 導出爲環境變量後,在子 Shell 中就可使用了。
這種形式是在定義變量 a 之後再將它導出爲環境變量,若是想在定義的同時導出爲環境變量,能夠寫做。
注意,本節咱們一直強調的是環境變量在子 Shell 中有效,並無說它在全部的 Shell 種有效;若是你經過終端建立一個新的 Shell,那麼它就不是當前 Shell 的子 Shell,環境變量對這個 Shell 就是無效的。
此外,經過命令導出的環境變量是臨時的,關閉 Shell 會話後它就銷燬了。因此,這種環境變量也只是在局部範圍內起做用,並不影響全部 Shell。
若是想讓環境變量在全部 Shell 中都有效,而且可以永久保存,在關閉 Shell 後也不丟失,那麼就須要把環境變量寫入啓動文件。至於如何寫入文件,請你們自行百度,這裏就再也不贅述了。
export aexport a=22export

Shell字符串

字符串是shell編程中最經常使用最有用的數據類型(除了數字和字符串,也沒啥其它類型好用了),字符串能夠用單引號,也能夠用雙引號,也能夠不用引號。單雙引號的區別跟PHP相似。

單引號

str='this is a string'

單引號字符串的限制

  • 單引號裏的任何字符都會原樣輸出,單引號字符串中的變量是無效的
  • 單引號字串中不能出現單獨一個的單引號(對單引號使用轉義符後也不行),但可成對出現,做爲字符串拼接使用。

雙引號

#!/bin/bash
ordernum='32782974960173'
# 雙引號裏既能夠有變量又能夠有轉義
orderdetail="this is the order $ordernum detail info, find it by \\"
echo $ordernum
echo $orderdetail

輸出結果爲:

32782974960173
this is the order 32782974960173 detail info, find it by \

雙引號的優勢:

  • 雙引號裏能夠有變量
  • 雙引號裏能夠出現轉義字符

拼接字符串

#!/bin/bash
datestr='2018-01-01'
timestr='11:11:11'
# 雙引號拼接
echo '雙引號拼接字符串'
currentdatetime_1="now time is "$datestr" "$timestr" !"
currentdatetime_2="now time is ${datestr}+${timestr} 。"
echo $currentdatetime_1 $currentdatetime_2
# 單引號拼接
echo '單引號拼接字符串'
currentdatetime_11='now time is '$datestr' '$timestr' !'
currentdatetime_22='now time is ${datestr}+${timestr} 。'
echo $currentdatetime_11 $currentdatetime_22

輸出結果爲:

雙引號拼接字符串
now time is 2018-01-01 11:11:11 ! now time is 2018-01-01+11:11:11 。
單引號拼接字符串
now time is 2018-01-01 11:11:11 ! now time is ${datestr}+${timestr} 。

獲取字符串長度

#!/bin/bash
datestr='2018-01-01'
echo $datestr 的長度爲: ${#datestr}
結果
2018-01-01 的長度爲: 10

提取子字符串(截取)

如下實例從字符串第 1 個字符開始截取 4 個字符:

#!/bin/bash
datestr='2018-01-02'
echo  日期【 $datestr 】的年爲: ${datestr:0:4} 

結果

日期【 2018-01-02 】的年爲: 2018

查找子字符串

查找字符 - 或 : 的位置(哪一個先出現就計算哪一個):

#!/bin/bash
datestr='2018-01-02 11:11:11'
echo `expr index "$datestr" -:`

結果:

5     

注意: 以上腳本中 ` 是反引號,而不是單引號 ',不要看錯了哦。

Shell 數組

bash支持一維數組(不支持多維數組),而且沒有限定數組的大小。

相似於 C 語言,數組元素的下標由 0 開始編號。獲取數組中的元素要利用下標,下標能夠是整數或算術表達式,其值應大於或等於 0。

定義數組

在 Shell 中,用括號來表示數組,數組元素用"空格"符號分割開。定義數組的通常形式爲:

數組名=(值1 2 ... n)

例如:

array_name=(value0 value1 value2 value3)

或者

array_name=(
value0
value1
value2
value3
)

還能夠單獨定義數組的各個份量:

array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen

能夠不使用連續的下標,並且下標的範圍沒有限制

讀取數組

讀取數組元素值的通常格式是:

${數組名[下標]}

例如:

valuen=${array_name[n]}

使用 @ 符號能夠獲取數組中的全部元素,例如:

echo ${array_name[@]}

獲取數組的長度

獲取數組長度的方法與獲取字符串長度的方法相同,例如:

# 取得數組元素的個數
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得數組單個元素的長度
lengthn=${#array_name[n]}

Shell 註釋

以 # 開頭的行就是註釋,會被解釋器忽略。

經過每一行加一個 # 號設置多行註釋,像這樣:

#--------------------------------------------
# 這是一個註釋
# author:菜鳥教程
# site:www.runoob.com
# slogan:學的不只是技術,更是夢想!
#--------------------------------------------
##### 用戶配置區 開始 #####
#
#
# 這裏能夠添加腳本描述信息
# 
#
##### 用戶配置區 結束  #####

若是在開發過程當中,遇到大段的代碼須要臨時註釋起來,過一下子又取消註釋,怎麼辦呢?

每一行加個#符號太費力了,能夠把這一段要註釋的代碼用一對花括號括起來,定義成一個函數,沒有地方調用這個函數,這塊代碼就不會執行,達到了和註釋同樣的效果

多行註釋

多行註釋還可使用如下格式:

:<<EOF
註釋內容...
註釋內容...
註釋內容...
EOF

EOF 也可使用其餘符號:

:<<'
註釋內容...
註釋內容...
註釋內容...
'

:<<!
註釋內容...
註釋內容...
註釋內容...
!
相關文章
相關標籤/搜索