《前端運維》一、Linux基礎--04Shell變數

Zaking發表於2022-03-19

這一篇文章,我們就要開始學習正式的Shell語言部分的內容。那在開始之前,我們回憶一下,javascript語言,大體都包含了哪些內容?比如資料型別(物件、字串、數值),資料結構(物件、陣列)、運算子(加減乘除與或非等)、流程控制(就是if-else,for迴圈等)等等,那麼其實不單單是javascript語言,其他任何語言所涉及到的內容也無非如此,只不過可能在此基礎上有些具體細節的不同。那麼同樣的,我們學習Shell也十分類似。

一、變數的定義

shell裡變數的定義很簡單,就像這樣:

varname='abcd'  

要注意,Shell裡變數的定義,也就是變數的宣告,並沒有像js那樣需要使用變數宣告的關鍵字。只是像上面那樣,賦值既宣告。

那麼在Shell裡,變數的定義要有幾點需要注意:

  1. 變數名和等號之間不能有空格
  2. 命名只能使用英文字母、數字和下劃線,首字母不能是數字
  3. 變數名中間不能有空格,可以使用下劃線
  4. 不能使用標點符號
  5. 不能使用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[*]}

結果大家自己去試一下哦。

五、環境變數配置檔案

最後,我們來看一下環境變數相關的配置檔案。

  1. /etc/profile,儲存系統變數,就是就是環境變數,對所有使用者生效。
    • 該檔案登入作業系統時,為每個使用者設定環境資訊,當使用者第一次登入時,該檔案被執行。也就是說這個檔案對每個shell都有效,用於獲取系統的環境資訊。
  2. /etc/bashrc,為每一個執行bash shell的使用者執行此檔案,當bash shell被開啟時,該檔案被讀取。也就是說,當使用者通過bash執行了shell時,執行這個檔案。
  3. ~/.bash_profile,它會呼叫~/.bashrc。可以再該檔案修改PATH路徑。僅對當前使用者有效。
  4. ~/.bashrc,儲存別名,可在該檔案修改alias,它最終會呼叫/etc/bashrc。僅對當前使用者有效。

在系統啟動時,上面四個檔案的執行順序是:1->3->4->2。

這裡要提一下,當修改以上檔案時,需要將系統登出後重新登入,但是我們可以使用source [檔案路徑] 的方式,使其立即生效。

我們再來看看其他幾個有用的檔案:

  1. ~/.bash_logout,登出時生效的環境變數配置檔案。
  2. ~/.bash_history,正確退出計算機的時候會歷史記錄會寫入檔案。
  3. /etc/issue,本地終端歡迎資訊。
  4. /etc/issue.net,遠端終端歡迎資訊。
  5. /etc/motd,不管遠端還是本地都可以生效 。

  

相關文章