bash-高級編程--變量和參數介紹


變量是什麼,變量是腳本編程中進行數據表現的一種方法,說白了,變量不過是計算機爲了保留數據項,而在內存中分配的一個位置或一組位置的標識或名字。

變量的替換

變量的名字就是保存變量值的地方,引用變量的值就叫做變量替換

$

shell中要仔細區分變量的名字和變量的值,如果a是一個變量,那麼$a就是引用這個變量的值,即變量所包含的數據。

andrew@andrew-Thurley:/work/linux-sys/bash$a=1
andrew@andrew-Thurley:/work/linux-sys/bash$ echo a 
a
andrew@andrew-Thurley:/work/linux-sys/bash$ echo $a
1

當變量裸體出現的時候,也就是說沒有$前綴的時候,那麼變量可能存在如下幾種情況

  1. 變量被聲明或被賦值
  2. 變量被unset
  3. 變量被exporte
  4. 或者處在一種特殊的情況下,變量代表一種信號

trap.sh

#!/bin/bash
# 使用trap來捕捉變量值.

trap 'echo Variable Listing --- a = $a b = $b' EXIT
# EXIT是腳本中exit命令所產生信號的名字.
#
# "trap"所指定的命令並不會馬上執行,
#+ 只有接收到合適的信號, 這些命令纔會執行.
echo "This prints before the \"trap\" --"
echo "even though the script sees the \"trap\" first."
echo
a=39
b=36
exit 0
andrew@andrew-Thurley:/work/linux-sys/bash/2.基本/src$ bash trap.sh 
This prints before the "trap" --
even though the script sees the "trap" first.

Variable Listing --- a = 39 b = 36

被一雙引號""括起來的變量替換是不會被阻止的,所以雙引號被稱爲部分引用,有的時候又被稱爲弱引用。如果是使用單引號的話''那麼比變量的替換就會被禁止,變量名只會被解釋成字面的意思,不會出發變量的替換。所以單引號被稱爲全引用,有的時候被稱爲強引用

#!/bin/bash

# 變量賦值和替換

a=375
hello=$a

#------------------------------------------------------------------
# 強烈注意, 在賦值的的時候, 等號前後一定不要有空格.
# 如果出現空格會怎麼樣?
 
# "VARIABLE =value"
#
#% 腳本將嘗試運行一個"VARIABLE"的命令, 帶着一個"=value"參數.

# "VARIABLE= value"
#
#% 腳本將嘗試運行一個"value"的命令,
#+ 並且帶着一個被賦值成""的環境變量"VARIABLE".
#------------------------------------------------------------------
echo hello
# 沒有變量引用, 只是個hello字符串.
echo $hello
echo ${hello} # 同上.

echo "$hello"
echo "${hello}"

echo

hello="A B C D"
echo $hello
# A B C D
echo "$hello" # A B C D
# 就象你看到的echo $hello和echo "$hello"將給出不同的結果.
# ===============================================================
# 引用一個變量將保留其中的空白, 當然, 如果是變量替換就不會保留了.
# ===============================================================

echo

echo '$hello' # $hello
#
# 全引用的作用將會導致"$"被解釋爲單獨的字符,
#+ 而不是變量前綴.

# 注意這兩種引用所產生的不同的效果.

# 設置爲空值.
hello=    

echo "\$hello (null value) = $hello"
# 注意設置一個變量爲null, 與unset這個變量, 並不是一回事
#+ 雖然最終的結果相同(具體見下邊).
 
# --------------------------------------------------------------

# 可以在同一行上設置多個變量,
#+ 但是必須以空白進行分隔.
# 慎用, 這麼做會降低可讀性, 並且不可移植.

var1=21 var2=22 var3=$V3
echo
echo "var1=$var1
var2=$var2
var3=$var3"
 
# 在老版本的"sh"上可能會引起問題.

# --------------------------------------------------------------

echo; echo

numbers="one two three"
#
other_numbers="1 2 3"
#

# 如果在變量中存在空白, If there is whitespace embedded within a variable,
#+ 那麼就必須加上引用.
# other_numbers=1 2 3
# 給出一個錯誤消息.
echo "numbers = $numbers"
echo "other_numbers = $other_numbers"
# other_numbers = 1 2 3
# 不過也可以採用將空白轉義的方法.
mixed_bag=2\ ---\ Whatever
#在轉義符後邊的空格(\).
 
echo "$mixed_bag"
# 2 --- Whatever

echo; echo

echo "uninitialized_variable = $uninitialized_variable"
# Uninitialized變量爲null(就是沒有值).
uninitialized_variable=
# 聲明, 但是沒有初始化這個變量,
 
#+ 其實和前邊設置爲空值的作用是一樣的.
echo "uninitialized_variable = $uninitialized_variable"
 
# 還是一個空值.
 
uninitialized_variable=23
# 賦值.
unset uninitialized_variable
# Unset這個變量.
echo "uninitialized_variable = $uninitialized_variable"
 
# 還是一個空值.
echo
 
exit 0

像C語言中的變量一樣,一個未初始化的變量將會是null值 - 就是未賦值(但並不代表值是0),在給變量 賦值之前就使用這個變量通常會引起問題。

### 小知識加油站–trap

trap的格式如下,功能就是捕捉信號,並對信號進行處理

trap [-lp] [[arg] sigspec ...]

trap使用官方簡介

  trap

  Automatically execute commands after receiving signals by processes or the operating system.
  Can be used to perform cleanups for interruptions by the user or other actions.

  - List available signals to set traps for:
    trap -l

  - List active traps for the current shell:
    trap -p

  - Set a trap to execute commands when one or more signals are detected:
    trap 'echo "Caught signal SIGHUP"' SIGHUP

  - Remove active traps:
    trap - SIGHUP SIGINT

  • arg可以是shell命令或者自定義函數
  • sigspec可以是以下的一個或多個
  • 定義在<signal.h>中的信號名或者數值。信號名的大小寫不敏感,SIG這個前綴也是可選的。以下的命令的效果都是一樣的
trap "echo SIGINT" SIGINT
trap "echo SIGINT" sigint
trap "echo SIGINT" 2
trap "echo SIGINT" int 
trap "echo SIGINT" Int

調試腳本時,trap經常用到的信號量

  • EXIT:在shell退出前執行trap設置的命令,也可以指定爲0
  • RETURN:在.和``source執行其他腳本返回時,執行trap`設置的命令
  • DEBUG:在任何命令執行前執行trap設置的命令,但對於函數僅在函數的第一條命令前執行一次
  • ERR:在命令結果爲非0時,執行trap設置的命令
#! /bin/bash
# 使用trap實現在每個函數開始之前打印以便打印,這樣就能準確的定位到函數的位置
# 從而實現對腳本的調試
trap "echo before a func is called" DEBUG
# 當. 或者 source 調用結束的時候出發
trap "echo . or source is called "  RETURN
func()
{

    echo "不管你信不信,這是一個函數"
    exit 0
}
# 測試
echo "call ."
. traptest

# 函數的調用
func
# DEBUG 查看調試信號是否有效的設置了
# trap -p RETURN
# trap -p DEBUG

exit 0

執行結果

andrew@andrew-Thurley:/work/linux-sys/bash/2.基本/src$ bash trap_func.sh 
before a func iis called
before a func iis called
call .
before a func iis called
. or source is called
before a func iis called
不管你信不信,這是一個函數
  • trap -l:列出所有信號的數值和名字,類似於kill -l
andrew@andrew-Thurley:~$ trap -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	
  • trap -p:列出通過trap設置過的信號處理命令
andrew@andrew-Thurley:~$ trap -p
trap -- 'name ' SIGINT
trap -- '' SIGTSTP
trap -- '' SIGTTIN
trap -- '' SIGTTOU
trap -- 'name ' RETURN
trap "" sigspec :忽略sigspec指定的信號
trap "do something" sigspec:收到sigspec指定的信號時,do some thing後,繼續執行後續命令。
trap sigspec or trap - sigspec:恢復sigspec指定的信號的默認行爲

注意

  • 在函數中設置的trap也是全局生效的
#!/bin/bash
# trap設置在函數中的tap也是全局有效的
foo()
{    
    trap "echo func is called" DEBUG 
}

# 輸出 func is called
foo
# 調試觸發
#trap -p DEBUG
# 輸出trap -- 'echo func is called' SIGINT
exit 0
  • 對於同一個信號,只有最後一次trap生效
  • trap只在本進程內有效,它的子進程不會繼承trap的設置。

使用trap設計一個用於反應程序執行過程的腳本

#!/bin/bash
# 使用trap來捕捉變量值.

# EXIT代表在函數退出前,執行trap
trap 'echo Variable Listing --- ret=${ret}' EXIT

ps -A
if [ $? == 0 ];then
    echo "commond exec OK!"
    ret=0
else
    ret=1
fi

echo "注意這裏,還沒有調用trap"

# trap是在退出的時候清理程序時調用的
exit 0

變量的賦值

=

賦值操作(前後都不能有空白)

注意:因爲=-eq都可以用作條件測試操作,所以不要與這裏的賦值操作相混淆。

=既可以用作條件測試操作,也可以用於賦值操作,這需要視具體上下文而定

簡單的變量賦值

#!/bin/bash
# "裸體"變量
echo
# 變量什麼時候是"裸體"的, 比如前邊少了$的時候?
# 當它被賦值的時候, 而不是被引用的時候.
# 賦值
a=879
echo "The value of \"a\" is $a."
# 使用'let'賦值
let a=16+5
echo "The value of \"a\" is now $a."
echo
# 在'for'循環中(事實上, 這是一種僞賦值):
echo -n "Values of \"a\" in the loop are: "
for a in 7 8 9 11
do
 echo -n "$a "
done
echo
echo
# 使用'read'命令進行賦值(這也是一種賦值的類型):
echo -n "Enter \"a\" "
read a
echo "The value of \"a\" is now $a."
echo

exit 0

簡單又不簡單的的兩種類型的變量賦值

#!/bin/bash
a=23
# 簡單的賦值
echo $a
b=$a
echo $b
# 現在讓我們來點小變化(命令替換).
a=`echo Hello!`
# 把'echo'命令的結果傳給變量'a'
echo $a
# 注意, 如果在一個#+的命令替換結構中包含一個(!)的話,
#+ 那麼在命令行下將無法工作.
#+ 因爲這觸發了Bash的"歷史機制."
# 但是, 在腳本中使用的話, 歷史功能是被禁用的, 所以就能夠正常的運行.
a=`ls -l`
echo $a
echo
echo "$a"
exit 0

使用$(...)機制來進行變量賦值(這是一種比後置引用(反引號`)更新的一種方法). 事實上這兩種
方法都是命令替換的一種形式.

# From /etc/rc.d/rc.local
R=$(cat /etc/redhat-release)
arch=$(uname -m)

bash變量是不區分類型的

不像其他程序語言一樣,bash並不區分變量的類型,本質上bash變量都是字符串。實際的作用依賴於上下文,Bash也允許比較操作和整數操作,其中的關鍵因素就是,變量中的值是否只有數值。

#!/bin/bash
# int-or-string.sh: 整型還是字符串?

a=2334 #整型.
let "a += 1"
echo "a = $a " # a = 2335
echo  # 還是整型.
b=${a/23/BB}
# 將"23"替換成"BB".
# 這將把變量b從整型變爲字符串.
echo "b = $b"
# b = BB35
declare -i b
# 即使使用declare命令也不會對此有任何幫助.
echo "b = $b"
# b = BB35
let "b += 1"
# BB35 + 1 =
echo "b = $b"
# b = 1
echo
c=BB34
echo "c = $c"
# c = BB34
d=${c/BB/23}
# 將"BB"替換成"23".
# 這使得變量$d變爲一個整形.
echo "d = $d"
# d = 2334
let "d += 1"
# 2334 + 1 =
echo "d = $d"
# d = 2335
echo

# null變量會如何呢?
e=""
echo "e = $e"
# e =
let "e += 1"
# 算術操作允許一個null變量?
echo "e = $e"
# e = 1
echo
# null變量將被轉換成一個整型變量.
 
# 如果沒有聲明變量會怎樣?
echo "f = $f"
# f =
let "f += 1"
# 算術操作能通過麼?
echo "f = $f"
# f = 1
echo
# 未聲明的變量將轉換成一個整型變量.
# 所以說Bash中的變量都是不區分類型的.
exit 0

不區分變量的類型既是幸運的事情也是悲慘的事情. 它允許你在編寫腳本的時候更加的靈活(但是也足
夠把你搞暈!), 並且可以讓你能夠更容易的編寫代碼. 然而, 這也很容易產生錯誤, 並且讓你養成糟糕
的編程習慣.

這樣的話, 程序員就承擔了區分腳本中變量類型的責任. Bash是不會爲你區分變量類型的

特殊變量類型

局部變量

這種變量只有代碼塊或者函數中才可見

如果變量用local 來聲明, 那麼它就只能夠在該變量被聲明的代碼塊中可見. 這個代碼塊就是局
部"範圍". 在一個函數中, 一個局部變量只有在函數代碼塊中才有意義.

環境變量

這種變量將影響用戶接口和shell的行爲

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章