這一篇文章,我們就要開始學習正式的Shell語言部分的內容。那在開始之前,我們回憶一下,javascript語言,大體都包含了哪些內容?比如資料型別(物件、字串、數值),資料結構(物件、陣列)、運算子(加減乘除與或非等)、流程控制(就是if-else,for迴圈等)等等,那麼其實不單單是javascript語言,其他任何語言所涉及到的內容也無非如此,只不過可能在此基礎上有些具體細節的不同。那麼同樣的,我們學習Shell也十分類似。
一、變數的定義
shell裡變數的定義很簡單,就像這樣:
varname='abcd'
要注意,Shell裡變數的定義,也就是變數的宣告,並沒有像js那樣需要使用變數宣告的關鍵字。只是像上面那樣,賦值既宣告。
那麼在Shell裡,變數的定義要有幾點需要注意:
- 變數名和等號之間不能有空格
- 命名只能使用英文字母、數字和下劃線,首字母不能是數字
- 變數名中間不能有空格,可以使用下劃線
- 不能使用標點符號
- 不能使用bash裡的關鍵字
Ok,我們知道了怎麼來定義一個變數,那Shell中的資料型別有哪些呢?shell中的資料型別比較特殊,從個人理解來說,Shell裡只有字串,其他的運算,比如數學運算,邏輯運算,都需要運算子或命令的參與。後面到運算子一篇的時候會詳細的說明。這裡先給大家打個預防針。當然,通過特定的方式可以宣告類似數值、陣列這樣的資料,但是實際上,個人覺得它是通過命令定義的方式來實現了資料型別的特徵,實際上他本質仍舊是個字串。只是通過特定的命令,賦予了它計算的能力而已。這個我們後面再聊。
那,我們現在知道了怎麼定義一個變數,接下來,我們在之前建立好的test.js檔案中寫點程式碼吧:
#!/bin/bash a=1 b=2 c=3 echo $a $b $c
然後,我們上傳到伺服器後,執行該檔案就可以了,如果不知道怎麼使用的,請到上一篇文章查詢,這裡不再多說,結果可想而知:
從上面的程式碼可以看到,我們使用剛定義好的變數是通過美元符號+變數名的形式,或者可以通過給變數名加上花括號的形式,這兩種方式是等價的:
#!/bin/bash a=1 b=2 c=3 echo ${a} ${b} ${c}
推薦在使用變數的時候,給所有的變數都加上花括號,養成一個良好的習慣。
二、變數的分類
變數的分類,並不是指資料型別,而是指有哪些型別的變數。注意!是變數的型別,而不是資料的型別。
首先,在Shell中變數大體可以分為三種型別:
- 區域性變數(普通變數),在指令碼或命令中定義,僅在當前shell例項中有效,其他shell啟動的程式不能訪問
- 全域性變數(環境變數),所有的程式都可以訪問,必要時還可以自定義環境變數
- shell變數,有一部分是全域性變數,也有一部分是區域性變數。
在做了簡單地瞭解之後,我們深入的學習一下,加深我們對變數的分類的理解。
2.1、全域性變數
全域性變數其實主要就是環境變數,這種變數主要儲存的是系統操作環境的相關變數。常用的環境變數有:
變數名 | 含義 | 示例 |
---|---|---|
HOSTNAME | 主機名 | HOSTNAME=localhost |
SHELL | 當前的shell | SHELL=/bin/bash |
HISTSIZE | 歷史命令條數 | HISTSIZE=1000 |
SSH_CLIENT | 當前操作環境如果是用SSH連線的話,這裡會記錄客戶端IP | SSH_CLIENT=192.168.1.100 57596 22 |
USER | 當前登入的使用者 | USER=root |
這些,我們可以直接echo列印,看下這些環境變數的具體內容。
#!/bin/bash echo $PATH echo $USER echo $SHELL echo $HOSTNAME
列印結果如下:
剛才我們們檢視的這些環境變數,屬於BASH內建的環境變數,那麼我們是否可以自定義環境變數呢?答案是可以的。
我們先來看兩個命令:
- export命令,export [-fnp][變數名稱]=[變數設定值],用於設定或顯示環境變數
- -n,刪除指定的變數,但是實際上變數並未刪除,只是不會輸出到後續指令的執行環境中。
- env命令,檢視環境變數。
那我們來試一下:
#!/bin/bash export zaking=1234 env | grep zaking
這樣就可以了。
2.2、普通變數
普通變數比較好理解,就是我們自己建立的,可能需要在指令碼中使用的變數。我們來試試一個比較簡單的,完整的定義普通變數的例子:
#!/bin/bash name=zaking readonly age=18 job=web echo $name $age $job unset name echo $name $age $job unset age echo $name $age $job
先解釋下上面的幾個新命令:
- unset命令,刪除已定義的變數,注意unset不能刪除只讀變數
- readonly命令,使變數只讀
上面的結果就很容易猜到:
三、引數的傳遞
是實話,這個東西我不知道該不該放在這,它到底屬於什麼,它屬於變數分類裡面的那個shell變數的型別麼?還是說它不是變數?但是它為什麼又有變數的特徵,你說它是運算子呢?它又不參與運算。所以,它看起來像是一個用符號表示的變數。我們下面就看看它們都是什麼吧:
3.1、位置引數變數
變數 | 作用 |
---|---|
$n | n為數字,$0代表命令本身,$1-$9代表第1到第9個引數,10以上的引數需要用大括號包含,如${10} |
$* | 這個變數代表命令中所有的引數,$*把所有的變看數看成一個整體 |
$@ | 這個變數也代表命令列中所有的引數,不過$@把每個引數進行區分 |
$# | 這個變數代表命令列中所有引數的個數 |
我們們來具體看下程式碼,就知道咋回事了:
#!/bin/bash echo "我開始了"echo "第一個引數為:$1"echo "第二個引數為:$2"echo "引數個數為:$#"echo "傳遞的引數作為一個字串顯示:$*"echo "傳遞的引數作為$#個字串顯示:$@"
列印的結果就是:
所以這些從使用的角度來說其實還好,並不複雜,記下來就是了,但是從類別的角度來說,我真沒找到具體的資料它屬於哪一個類別。哎...我們繼續吧。
3.2、預定義變數
簡單說就是指令碼中預先定義好的變數,變數名不能自定義,變數的作用也是固定的:
變數 | 作用 |
---|---|
$? | 最後一次執行的命令的返回狀態。0表示正確執行,非0表示不正確執行 |
$$ | 當前程式的程式號(PID) |
$! | 後臺執行的最後一個程式的ID號 |
$- | 顯示Shell使用的當前選項,與set命令功能相同。 |
也沒啥好說的。對吧?大家自己列印看一下吧。
3.3、read命令
該命令用於從標準輸入裝置讀取引數。它有幾個選項,很有用:
- -p,後面跟提示資訊,在輸入前列印提示資訊
- -t,後面跟秒數,定義輸入字元的等待時間
- -n,後面跟數字,定義輸入文字的長度
- -s,安靜模式,在輸入字元時不在螢幕上顯示,一般用於密碼輸入使用
- -e,在輸入的時候可以使用命令補全功能
我們還是來看個例子吧:
#!/bin/bash read -p 'please input your name:' -t 5 name echo -e "\n" read -p 'please input you gender:' -n 1 gender echo -e "\n" read -p 'please input your password:' -s password echo -e "\n" echo $name,$gender,$password
大家可以去執行一下試一試。
四、declare命令
還記在開始的時候,變數的定義的那一部分,我說了,個人感覺shell裡並沒有真正意義上的資料型別,只有字串。那麼下面通過declare命令的學習,我們來嘗試驗證一下我的論點。
declare命令的主要作用就是:宣告shell變數。注意,我沒說明是宣告什麼變數,只是宣告變數。
declare [+/-][rxi][變數名稱=設定值]
它常用的選項有這些:
- +/- "-"可用來指定變數的屬性,"+"則是取消變數所設的屬性。
- -a,將變數宣告為陣列型別。
- -i,將變數宣告為整數型別。
- -r,將變數宣告為只讀。
- -p,顯示指定變數被宣告的型別。
- -x,將變數宣告為環境變數。
這麼說,還比較模糊。我們們還是得實踐一下:
#!/bin/bash a=1 b=2 c=$a+$b echo $c declare -i c echo $c declare -i c=$a+$b echo $c
你猜,結果是什麼:
所以,就像我之前說的,這種感覺並不像是javascript中那樣,型別是一個純粹的值,它更像是一種屬性:
上面的結果,我在程式碼里加了兩行:
#!/bin/bash a=1 b=2 c=$a+$b echo $c declare -i c echo $c declare -i c=$a+$b echo $c echo '-------' declare -p c
所以,你看,它本身還是個字串罷了,只是賦予了一個屬性。讓系統對其進行分辨。
我們再來試一下其它的選項:
#!/bin/bash declare -x m=1 declare -p m env | grep m
大家自行試一下這個程式碼,看下結果是啥,下面我們再試一下陣列:
#!/bin/bash #宣告為陣列型別 declare -a arrs arrs[0]=zaking arrs[1]=wong #預設只列印第一個元素 echo ${arrs} #列印第2個元素 echo ${arrs[1]} #列印全部 echo ${arrs[*]}
結果大家自己去試一下哦。
五、環境變數配置檔案
最後,我們來看一下環境變數相關的配置檔案。
- /etc/profile,儲存系統變數,就是就是環境變數,對所有使用者生效。
- 該檔案登入作業系統時,為每個使用者設定環境資訊,當使用者第一次登入時,該檔案被執行。也就是說這個檔案對每個shell都有效,用於獲取系統的環境資訊。
- /etc/bashrc,為每一個執行bash shell的使用者執行此檔案,當bash shell被開啟時,該檔案被讀取。也就是說,當使用者通過bash執行了shell時,執行這個檔案。
- ~/.bash_profile,它會呼叫~/.bashrc。可以再該檔案修改PATH路徑。僅對當前使用者有效。
- ~/.bashrc,儲存別名,可在該檔案修改alias,它最終會呼叫/etc/bashrc。僅對當前使用者有效。
在系統啟動時,上面四個檔案的執行順序是:1->3->4->2。
這裡要提一下,當修改以上檔案時,需要將系統登出後重新登入,但是我們可以使用source [檔案路徑] 的方式,使其立即生效。
我們再來看看其他幾個有用的檔案:
- ~/.bash_logout,登出時生效的環境變數配置檔案。
- ~/.bash_history,正確退出計算機的時候會歷史記錄會寫入檔案。
- /etc/issue,本地終端歡迎資訊。
- /etc/issue.net,遠端終端歡迎資訊。
- /etc/motd,不管遠端還是本地都可以生效 。