天天看點

shell程式設計之變量

一、變量

1.變量的命名

shell中的變量必須以字母或者下劃線開頭,後面可以跟數字、字母和下劃線,變量長度沒有限制。

#正确的變量命名

firstname

FIRSTNAME

_helloworld

Fullname

big_data

Person01

#錯誤的變量命名

51paly #變量不能以數字開頭

*badname #變量不能以特殊字元開頭

PS1 #變量不能以特殊字元開頭

for #變量不能使用shell關鍵字

按照以上的變量命名規則定義變量abc,從理論上來說是可行的,但是一個好的習慣是變量最好能表明它代表的含義。比如說Student_ID,一看就知道它所表達的是“學号"的意思,絕對比number這種模棱兩可的變量要清晰得多名,不僅看代碼的人覺得簡單明了,而且有利于後期的代碼維護。更好地習慣則是加上一些注釋,但是也不要太過拘泥,如下所示:

#定義學号   #使用注釋解釋變量使後期閱讀更為清晰

Student_ID

#定義日期 #這種注釋就顯得有所拘泥

DATE

2.變量的指派和取值

#定義變量:變量名=變量值

#注意點一:變量名和變量值之間用等号緊緊相連,之間沒有任何空格

[root@Cfhost-170820-UCNK ~]# name=john

[root@Cfhost-170820-UCNK ~]# name = john

-bash: name: command not found

[root@Cfhost-170820-UCNK ~]# name="john"

#注意點二:當變量中有空格時必須用引号括起,否則會出現錯誤

#其中的引号可以是雙引号,也可以是單引号

[root@Cfhost-170820-UCNK ~]# name="john wang"

[root@Cfhost-170820-UCNK ~]# name=john wang

-bash: wang: command not found

變量取值很簡單,隻需要在變量名前加上$符号即可,嚴謹一點的寫法是${},如下所示:

[root@Cfhost-170820-UCNK ~]# echo $name

john wang

[root@Cfhost-170820-UCNK ~]# echo ${name}

#使用${}擷取變量值是一種相對比較保險的方式

[root@Cfhost-170820-UCNK ~]# name1="$name"

[root@Cfhost-170820-UCNK ~]# echo $name1

john

[root@Cfhost-170820-UCNK ~]# name1='$name'

[root@Cfhost-170820-UCNK ~]# echo name1

name1

由于Shell具有“弱變量"的特性,是以即便在沒有預先聲明變量的時候也可以引用的,而且沒有任何報錯或提醒,這可能會造成腳本中引用不正确的變量,進而導緻腳本異常,但是卻很難找出原因。在這種情況下,可以設定腳本運作時必須遵循“先聲明再使用"的原則,這樣一旦腳本中出現使用未聲明的變量的情況則立刻報錯。

[root@Cfhost-170820-UCNK ~]# echo $unDefinedVar

#因為該變量未聲明,是以值為空,但沒有任何報錯

#設定變量必須先聲明再使用

[root@Cfhost-170820-UCNK ~]# shopt -s -o nounset

-bash: unDefinedVar: unbound variable

3.取消變量

john #此時變量有值

[root@Cfhost-170820-UCNK ~]# unset name

-bash: name: unbound variable

#報錯為沒有綁定變量

#取消函數

unset_function(){

echo "Hello,World"

}

unset unset_function

unset_function #由于函數已經被取消,這裡調用會出錯

4.特殊變量

Shell中還有一些預先定義的特殊隻讀變量,它們的值隻有在腳本運作時才能确定。首先是”位置參數“,位置參數的命名簡單直接,比如,腳本本身為$0,第一個參數為$1,第二個參數為$2,第三個參數為$3,以此類推。當位置參數的個數大于9時,需要用${}括起來辨別,比如說第10個位置參數應該記為${10}。另外,$#表示腳本參數的個數總和,$@或$*表示腳本的所有參數。請看下面示例:

[root@Cfhost-170820-UCNK ~]# cat posion.sh

#!/bin/bash

echo "This script is name is: $0"

echo "$# Parameters in total"

echo "All parameters list as: $@"

echo "The first parameter is $1"

echo "The second parameter is $2"

echo "The third parameter is $3"

[root@Cfhost-170820-UCNK ~]# bash posion.sh a b c

This script is name is: posion.sh

3 Parameters in total

All parameters list as: a b c

The first parameter is a

The second parameter is b

The third parameter is c

腳本或指令傳回值:$?

在管理者登入到系統中互動式地輸入指令時,系統也會及時在螢幕上輸出内容給予回報。比如說本想使用ifconfig檢視網卡狀态,但是将指令錯寫成ifconfi,系統會立刻給出command not found 的提示,這種提示确實能讓管理者感覺到系統非常友好。

[root@Cfhost-170820-UCNK ~]# ifconfi

-bash: ifconfi: command not found

但是在很多背景腳本是需要每天自動運作的,比如說每天淩晨兩點的資料庫備份。在這種情況下一旦出錯是不可能在第一時間知道的。那靠什麼判斷出錯呢?

再考慮一個場景:有些自動備份腳本在按時完成本地資料備份後,還會複制一份放到遠端主機上(通過scp就可以做到)。不過在複制前需要先确認遠端主機是否還”活着",這可以通過ping遠端主機做到。如果能ping通則進行複制,如果ping不通則采取其他動作。這裡又如何判斷是否ping成功了呢?

這時就需要借助指令的傳回值來判斷了。Linux中規定正常退出的指令和腳本應該以0作為傳回值,任何非0的傳回值都表示指令未正确退出或未正常執行。

在第一個例子中,輸錯指令後立即檢視當時特殊變量$?的值為127;第二個例子中,ping不通某個位址時檢視當時的$?值為1.注意,$?永遠是上一個指令的傳回值,是以要檢視某個

指令的傳回值必須在運作該指令後立即檢視$?。在自動化腳本中,也可以通過$?變量的值判斷之前指令的執行狀态,進而采取不同的動作。

#輸入錯誤的指令時的傳回值

[root@Cfhost-170820-UCNK ~]# echo $?

127

 #嘗試ping主機ping不通時的傳回值

[root@Cfhost-170820-UCNK ~]# ping 192.168.160.66 -c 1

PING 192.168.160.66 (192.168.160.66) 56(84) bytes of data.

--- 192.168.160.66 ping statistics ---

1 packets transmitted, 0 received, 100% packet loss, time 10000ms

[root@Cfhost-170820-UCNK ~]# ^C

130

5.數組

數組是一種特殊的資料結構,其中每一項被稱為一個元素,對于每個元素,都可以用索引方式取出元素的值。使用數組的典型場景是一次性要記錄很多類型相同的資料時(但不是說一定要相同,因為Shell變量是弱類型的,并不要求數組的每個元素都是相同類型)。比如,為了記錄班級中所有人的計算機成績,如果不用數組來處理就隻能定義所有人成績的變量,這就會顯得非常繁瑣。Shell中的數組對元素個數沒有限制,但是隻支援一維數組,這一點和許多語言不同。

a.數組的定義

數組的定義方法如下:用declare指令定義數組Array,并将第一個元素指派為0,第二個元素指派為1,其下标(也就是索引)則分别是0和1(記住數組的索引從0開始計數的),然後列印出第一個元素的值

#定義名為Array的索引數組

[root@Cfhost-170820-UCNK ~]# declare -a Array

#數組的下标從0開始計數,定義了第一個元素值為0,第二個元素值為1

[root@Cfhost-170820-UCNK ~]# Array[0]=0

[root@Cfhost-170820-UCNK ~]# Array[1]=1

如果說數組Array的前兩個元素“類型相同"(嚴格意義上這麼說是不對的),那麼第三個元素就顯得”另類"了:指派為一個字元串。這又一次驗證了Shell變量是弱類型的,這在很多語言中是不可能的。

[root@Cfhost-170820-UCNK ~]# Array[2]="HelloWorld"

和其他變量一樣,Shell對于數組變量的聲明也非常寬松,而且随時都可以根據需要增加變量中的元素。相比其他語言,Shell的資料更為靈活。在很多語言中,一旦對數組進行初始化就不能改變其大小了。

[root@Cfhost-170820-UCNK ~]# Array[2]"HelloWorld"

-bash: Array[2]HelloWorld: command not found

[root@Cfhost-170820-UCNK ~]# declare -a Name=('john','sue')

[root@Cfhost-170820-UCNK ~]# Name[2]='wang'

[root@Cfhost-170820-UCNK ~]# Name=('john' 'sue')

[root@Cfhost-170820-UCNK ~]# Score=([3]=3 [5]=5 [7]=7)

#數組在建立的時候同時指派

[root@Cfhost-170820-UCNK ~]# declare -a Name=('john' 'sue')

#增加元素

#更簡單的建立數組的方式--不使用declare關鍵字

還可以給特定的元素指派。下面的執行個體就是隻對第四個、第六個、第八個元素進行指派

#跳号指派

#數組取值:知道了如何定義數組和指派元素後,下面就要了解數組一些常見操作。最簡單的操作就是數組取值,其格式為:${數組名[索引]}.比之前定義的數組Array、Name為例,取值示範如下·:

[root@Cfhost-170820-UCNK ~]# echo ${Array[0]}

[root@Cfhost-170820-UCNK ~]# echo ${Array[2]}

HelloWorld

[root@Cfhost-170820-UCNK ~]# echo ${Name[0]}

[root@Cfhost-170820-UCNK ~]# echo

[root@Cfhost-170820-UCNK ~]# echo ${Name[1]}

sue

#指定索引,隻能取單個值,要是想一次性取出所有元素的值,可以采取以下兩種方式:

[root@Cfhost-170820-UCNK ~]# echo ${Array[@]}

0 1 HelloWorld

[root@Cfhost-170820-UCNK ~]# echo ${Array[*]}

從表面上看兩者沒有什麼差別,但是${Array[@]}得到的是以空格隔開的元素值,而${Array[*]}的輸出是整個字元串。

數組長度:即數組個數。利用"@"或"*“字元,可以将數組擴充成清單,然後使用"#"來擷取數組元素的個數,如下所示:

[root@Cfhost-170820-UCNK ~]# echo ${#Array[@]}

3

[root@Cfhost-170820-UCNK ~]# echo ${#Array[*]}

如果某個元素是字元串,還可以通過指定索引的方式獲得該元素長度,如下所示:

[root@Cfhost-170820-UCNK ~]# echo ${#Array[2]}

10

 數組截取:可以截取某個元素的一部分,對象可以是整個數組或某個元素。

#取出數組的第一、第二個元素

[root@Cfhost-170820-UCNK ~]# echo ${Array[@]:1:2}

1 HelloWorld

#取出第二個元素從第0個字元開始連續5個字元

[root@Cfhost-170820-UCNK ~]# echo ${Array[2]:0:5}

Hello

#l連接配接數組:将n個數組進行拼接操作

[root@Cfhost-170820-UCNK ~]# Conn=($Array[@] ${Name[@]})

[root@Cfhost-170820-UCNK ~]# echo ${Conn[@]}

0[@] john sue

#取消數組或元素:和取消一般變量一樣,取消一個數組的方式也可以使用unset指令

#取消數組中的一個元素

[root@Cfhost-170820-UCNK ~]# unset Array[1]

#取消整個數組

0 HelloWorld

[root@Cfhost-170820-UCNK ~]# unset Array

[root@Cfhost-170820-UCNK ~]# 4{Array[@]}

-bash: 4{Array[@]}: command not found

 6.隻讀變量

隻讀變量又稱常量,是通過readonly内建指令建立的變量。這種變量在聲明時就·要求指派,并且之後無法修改,這和之前講的使用declare -r 聲明隻讀變量的效果是一緻的。

[root@Cfhost-170820-UCNK ~]# readonly RO=100

[root@Cfhost-170820-UCNK ~]# RO=200

-bash: RO: readonly variable

7.變量的作用域

變量的作用域又叫命名空間,表示變量的上下文。相同的變量可以在多個命名空間中定義,并且彼此之間互不幹涉,是以在一個新的命名空間中可以自定義任何變量,因為所定義的變量都隻在各自命名空間中。

在Linux系統中,不同程序ID的shell預設為一個不同的命名空間。

Shell變量的作用域是在本Shell内,屬于本Shell的全局變量,也就是從定義該變量的地方開始到結束,或到主動使用unset删除該變量的地方為止。在變量的作用域内,該變量是可見的,在函數内對變量也是可以通路的、可修改的,這和C語言不同。