Shell(1)---變量

Shell(1)---變量

初衷:學習shell的目的很簡單,本身常常在linux服務器上作各類操做,並且基本上是一些相同的命令操做,因此就想經過shell腳原本啓動就行,可以節省必定的開發時間,提升工做效率。html

1、shell變量

一、定義變量

Shell 支持如下三種定義變量的方式mysql

xub$ name=value
xub$ name='value'
xub$ name="value"
# name 是變量名,value 是賦給變量的值。

區別linux

若是 value 不包含任何空白符(例如空格、Tab 縮進等),那麼能夠不使用引號;sql

若是 value 包含了空白符,那麼就必須使用引號包圍起來。shell

使用單引號和使用雙引號也是有區別的 下面講。編程

注意 賦值號=的兩邊不能有空格。bash

xub$ name="小小"  #賦值
xub$ echo $name  #輸出命令
xub$ 小小         #輸出

二、使用變量

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

xub$ home="千島湖"
xub$ echo $home
千島湖
xub$ echo ${home}
千島湖

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

xub$ name="xiaoxaio"
xub$ echo "my name is $namecc "
my name is  #發現這裏並無輸出變量名 由於系統認爲$namecc是一個總體了

改爲函數

xub$ name="xiaoxaio"
xub$ echo "my name is ${name}cc "
my name is xiaoxaiocc  #這就是${}的優勢

三、單引號和雙引號的區別

上面說了定義變量時,變量的值單引號' ',和雙引號" "是有區別的 ,舉例以下

xub$ sex="女"
xub$ one='小小的性別是:${sex}'
xub$ two="小小的性別是:${sex}"
xub$ echo $one
小小的性別是:${sex} 
xub$ echo $two
小小的性別是:女

區別

  • 以單引號' '包圍變量的值時,單引號裏面是什麼就輸出什麼,即便內容中有變量和命令(命令須要反引發來)也會把它們原樣輸出。
  • 以雙引號" "包圍變量的值時,輸出時會先解析裏面的變量和命令,而不是把雙引號中的變量名和命令原樣輸出。

建議

1)若是變量的內容是數字,那麼能夠不加引號;

2)若是真的須要原樣輸出就加單引號;

3)其餘沒有特別要求的字符串等最好都加上雙引號。

四、只讀變量

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

xub$ name=zhangsan;readonly name;name=lisi  #這裏是三條命令 用;隔開
-bash: name: readonly variable  #報錯

五、刪除變量

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

xub$ unset variable_name

注意 unset 命令不能刪除只讀變量。

六、將命令的輸出結果賦值給變量

Shell 也支持將命令的執行結果賦值給變量,常見的有如下兩種方式:

xub$ name=`return`
xub$ name=$(return)

第一種方式把命令用反引號(位於 Esc 鍵的下方)包圍起來,反引號和單引號很是類似,容易產生混淆,因此不推薦使用這種方式;第二種方式把命令用$()包圍起來,區分更加明顯,因此推薦使用這種方式。

舉例1

xub$ name=$(cat name.text)  #把name.text文件內容賦值給name
xub$ echo $name  #輸出
你們好 我叫小小

舉例2,date 命令用來得到當前的系統時間,使用命令替換能夠將它的結果賦值給一個變量。

xub$ begin_time=`date`    #開始時間,使用``替換
xub$ sleep 20s            #休眠20秒
xub$ finish_time=$(date)  #結束時間,使用$()替換
xub$ echo "Begin time: $begin_time"
Begin time: 2019年 5月16日 星期四 22時37分46秒 CST
xub$ echo "Finish time: $finish_time"
Finish time: 2019年 5月16日 星期四 22時38分06秒 CST

使用 data 命令的%s格式控制符能夠獲得當前的 UNIX 時間戳,這樣就能夠直接計算腳本的運行時間了。

xub$ begin_time=`date +%s`    #開始時間,使用``替換
xub$ sleep 5s                 #休眠5秒
xub$ finish_time=$(date +%s)  #結束時間,使用$()替換
xub$ run_time=$((finish_time - begin_time))  #時間差
xub$ echo "begin time: $begin_time"
begin time: 1558017925
xub$ echo "finish time: $finish_time"
finish time: 1558017930
xub$ echo "run time: ${run_time}s"
run time: 5s

注意:若是被替換的命令的輸出內容包括多行(也即有換行符),或者含有多個連續的空白符,那麼在輸出變量時應該將變量用雙引號包圍,不然系統會使用默認的空白符來填充,這會致使換行無效,以及連續的空白符被壓縮成一個。請看下面的代碼:

xub$ ls=`ls -l | grep damo`
xub$ echo $ls  #不使用雙引號包圍
drwxr-xr-x 16 xub staff 544 5 15 14:27 adamo drwxr-xr-x 4 xub staff 136 3 21 17:27 damo
xub$ echo "$ls"  #使用雙引號包圍
drwxr-xr-x   16 xub  staff    544  5 15 14:27 adamo #發現使用雙引號纔會將變量內容分行
drwxr-xr-x    4 xub  staff    136  3 21 17:27 damo

總結 原則上講,上面提到的兩種變量替換的形式是等價的,能夠隨意使用;可是,反引號畢竟看起來像單引號,有時候會對查看代碼形成困擾,而使用 $() 就相對清晰,能有效避免這種混亂。並且有些狀況必須使用它,由於它支持嵌套,反引號不行。同時也要注意$() 僅在 Bash Shell 中有效,而反引號可在多種 Shell 中使用。


2、Shell位置參數

運行 Shell 腳本文件時咱們能夠給它傳遞一些參數,這些參數在腳本文件內部可使用$n的形式來接收,例如,$1 表示第一個參數,$2 表示第二個參數,依次類推。

這種經過$n的形式來接收的參數,在 Shell 中稱爲位置參數。

一、給腳本文件傳遞位置參數

請編寫下面的代碼,並命名爲family.sh

#!/bin/bash
# $1表明接收第一個傳進來的參數,$2表明第二個
echo "name: $1" 
echo "sex: $2"

運行family.sh

xub$ sh family.sh 小小 3歲  #傳入兩個參數 中間以空格分開
name: 小小       #輸出
sex: 3歲

二、給函數傳遞位置參數

一樣建立family.sh腳本

#!/bin/bash
#定義函數
function func(){
    echo "name: ${1}"
    echo "age: ${2}"
}
#調用函數
func 小小 3歲

運行family.sh腳本

xub$ sh family.sh #運行腳本
name: 小小    #輸出
age: 3歲

注意 若是參數個數太多,達到或者超過了 10 個,那麼就得用${n}的形式來接收了,例如 ${10}、${23}。{ }的做用是爲了幫助解釋器識別參數的邊界,這跟使用變量時加{ }是同樣的效果。


3、Shell 特殊變量及其含義

變量 含義
$0 當前腳本的文件名。
$n(n≥1) 傳遞給腳本或函數的參數。n 是一個數字,表示第幾個參數。例如,第一個參數是 $1,第二個參數是 $2。
$# 傳遞給腳本或函數的參數個數。
$* 傳遞給腳本或函數的全部參數。
$@ 傳遞給腳本或函數的全部參數。當被雙引號" "包含時,$@ 與 $* 稍有不一樣,咱們將在《Shell $*和$@的區別》一節中詳細講解。
$? 上個命令的退出狀態,或函數的返回值,咱們將在《Shell $?》一節中詳細講解。
$$ 當前 Shell 進程 ID。對於 Shell 腳本,就是這些腳本所在的進程 ID。

下面咱們經過兩個例子來演示。

一、給腳本文件傳遞參數

編寫下面的代碼,並保存爲family.sh

#!/bin/bash
echo "當前shell進程 ID: $$"
echo "第0個參數名稱: $0"
echo "第一個參數名稱: $1"
echo "第二個參數名稱: $2"
echo "全部參數名稱輸出方式一: $@"
echo "全部參數名稱輸出方式二: $*"
echo "傳遞給腳本或函數的參數個數: $#"

運行 family.sh

xub$ sh family.sh 張三 王老五  #運行腳本
當前shell進程 ID: 38745
第0個參數名稱: family.sh
第一個參數名稱: 張三
第二個參數名稱: 王老五
全部參數名稱輸出方式一: 張三 王老五
全部參數名稱輸出方式二: 張三 王老五
傳遞給腳本或函數的參數個數: 2

二、給函數傳遞參數

編寫下面的代碼,並保存爲 family.sh

#!/bin/bash
#定義函數
function fun(){
echo "當前shell進程 ID: $$"
echo "第0個參數名稱: $0"
echo "第一個參數名稱: $1"
echo "第二個參數名稱: $2"
echo "全部參數名稱輸出方式一: $@"
echo "全部參數名稱輸出方式二: $*"
echo "傳遞給腳本或函數的參數個數: $#"
}
fun 李四 趙六

運行family.sh

xub$ sh family.sh 
當前shell進程 ID: 40243
第0個參數名稱: family.sh
第一個參數名稱: 李四
第二個參數名稱: 趙六
全部參數名稱輸出方式一: 李四 趙六
全部參數名稱輸出方式二: 李四 趙六
傳遞給腳本或函數的參數個數: 2

三、Shell $*和$@的區別

相同點:$* 和 $@ 都表示傳遞給函數或腳本的全部參數。當 $* 和 $@ 不被雙引號" "包圍時,它們之間沒有任何區別,都是將接收到的每一個參數看作一份數據,彼此之間以空格來分隔。

不一樣點:可是當它們被雙引號" "包含時,就會有區別了:

  • "$*"會將全部的參數從總體上看作一份數據,而不是把每一個參數都看作一份數據。
  • "$@"仍然將每一個參數都看做一份數據,彼此之間是獨立的。

好比傳遞了 5 個參數,那麼對於"$*"來講,這 5 個參數會合併到一塊兒造成一份數據,它們之間是沒法分割的;而對於"$@"來講,這 5 個參數是相互獨立的,它們是 5 份數據。

若是使用 echo 直接輸出"$*""$@"作對比,是看不出區別的;但若是使用 for 循環來逐個輸出數據,當即就能看出區別來。

示例

編寫下面的代碼,並保存爲 test.sh

#!/bin/bash
echo "開始遍歷參數 from \"\$*\""
for var in "$*"
do
    echo "$var"
done
echo "開始遍歷參數 from \"\$@\""
for var in "$@"
do
    echo "$var"
done

運行 test.sh,並附帶參數:

xub$ sh test.sh 小小 爸爸 媽媽
開始遍歷參數 from "$*"  #很明顯$*把我穿入的參數做爲一個總體
小小 爸爸 媽媽
開始遍歷參數 from "$@" # $@傳進來的參數是相互獨立的
小小
爸爸
媽媽

從運行結果能夠發現,對於"$*",只循環了 1 次,由於它只有 1 分數據;對於"$@",循環了 3 次,由於它有 3份數據。

四、Shell $?

$? 是一個特殊變量,用來獲取上一個命令的退出狀態,或者上一個函數的返回值。

所謂退出狀態,就是上一個命令執行後的返回結果。退出狀態是一個數字,通常狀況下,大部分命令執行成功會返回 0,失敗返回 1。不過,也有一些命令返回其餘值,表示不一樣類型的錯誤。

一、$? 獲取上一個命令的退出狀態

編寫下面的代碼,並保存爲 test.sh:

#!/bin/bash
if [ "$1" == 100 ]
then
   exit 0  #參數正確,退出狀態爲0
else
   exit 1  #參數錯誤,退出狀態1
fi

exit表示退出當前 Shell 進程,咱們必須在新進程中運行 test.sh,不然當前 Shell 會話(終端窗口)會被關閉,咱們就沒法取得它的退出狀態了。

例如,運行 test.sh 時傳遞參數 100:

xub$ bash ./test.sh 100  #做爲一個新進程運行
xub$ echo $?
0

再如,運行 test.sh 時傳遞參數 89:

xub$ bash ./test.sh 89  #做爲一個新進程運行
xub$ echo $?
1

二、 $? 獲取函數的返回值

編寫下面的代碼,並保存爲 test.sh:

#!/bin/bash
#獲得兩個數相加的和
function add(){
    return `expr $1 + $2`
}
add 23 50  #調用函數
echo $?  #獲取函數返回值

運行結果 73

注意:嚴格來講,Shell 函數中的 return 關鍵字用來表示函數的退出狀態,而不是函數的返回值;Shell 不像其它編程語言,沒有專門處理返回值的關鍵字。

參考

Shell腳本學習指南




只要本身變優秀了,其餘的事情纔會跟着好起來(少將13)
相關文章
相關標籤/搜索