變數和參數的介紹 變數替換 變數的名字就是變數儲存值的地方. 引用變數的值就叫做變數替換.“$“這個符號就好像是一種標誌讓我們仔細的區別變數的名字和變數的值. 如果variable是一個變數的名字, 那麼$variable就是引用這變數的值, 即這邊變數所包含的資料. [html] root@ubuntu:~# variable=12 root@ubuntu:~# echo variable variable root@ubuntu:~# echo $variable 12 當變數沒有$首碼的時候,那麼變數可能存在如下幾種情況.1.變數被聲明或被賦值, 2.變數被unset, 3.變數被exporte, 4.變數處在一種特殊的情況,變數代表一種訊號 變數賦值可以使用=(比如 var1=27), 也可以在read命令中或者迴圈頭進行賦值 (for var2 in 1 2 3). 被一對雙引號(" ")括起來的變數替換是不會被阻止的. 所以雙引號被稱為部分引用, 有時候又被稱為"弱引用". 但是如果使用單引號的話(' '), 那麼變數替換就會被禁止了, 變數名只會被解釋成字面的意思, 不會發生變數替換. 所以單引號被稱為全引用, 有時候也被稱為"強引用". 注意$variable事實上只是${variable}的簡寫形式. 在某些上下文中$variable可能會引起錯誤, 這時候你就需要用${variable}了 下面以一個例子做說明 [html] #!/bin/bash # 變數賦值和替換 a=375 #這裡沒有$說明是聲明並且賦值了 hello=$a #$a表示使用變數a的值,把這個值賦值給hello這個變數 #------------------------------------------------------------------------- # 強烈注意, 在賦值的的時候, 等號前後一定不要有空格. # 如果出現空格會怎麼樣? # "VARIABLE =value" # 指令碼將嘗試運行一個"VARIABLE"的命令, 帶著一個"=value"參數. # "VARIABLE= value" # 指令碼將嘗試運行一個"value"的命令, 並且帶著一個被賦值成""的環境變數"VARIABLE". #------------------------------------------------------------------------- echo hello #沒有$這裡列印hello變數的名字 echo $hello #列印hello變數的值 echo ${hello} #同樣是列印hello變數的值 echo "$hello" echo "${hello}" hello="A B C D" #重新賦值 echo $hello # A B C D 引用一個變數將保留其中的空白, 當然, 如果是變數替換就不會保留了. echo "$hello" # A B C D echo '$hello' hello= echo "\$hello (null value) = $hello" V3=23 var1=21 var2=22 var3=$V3 echo "var1=$var1 var2=$var2 var3=$var3" numbers="one two three" other_numbers="1 2 3" echo "numbers = $numbers" echo "other_numbers = $other_numbers" mixed_bag=2\ ---\ Whatever echo "$mixed_bag" echo "uninitialized_variable = $uninitialized_variable" uninitialized_variable= echo "uninitialized_variable = $uninitialized_variable" uninitialized_variable=23 unset uninitialized_variable echo "uninitialized_variable = $uninitialized_variable" exit 0 看看這個指令碼的執行結果:[html] root@ubuntu:~/resource/study/shell_study# ./value-test hello 375 375 375 375 A B C D A B C D $hello $hello (null value) = var1=21 var2=22 var3=23 numbers = one two three other_numbers = 1 2 3 2 --- Whatever uninitialized_variable = uninitialized_variable = uninitialized_variable = 一個未初始化的變數將會是"null"值 - 就是未賦值(但並不是代表值是0!). 在給變數賦值之前就使用這個變數通常都會引起問題. 但是在執行算術操作的時候, 仍然有可能使用未初始化過的變數 [html] root@ubuntu:~/resource/study/shell_study# echo "$data" root@ubuntu:~/resource/study/shell_study# let "data +=5" root@ubuntu:~/resource/study/shell_study# echo "$data" 5 結論:一個未初始化的變數是沒有值的, 但是在做算術操作的時候, 這個未初始化的變數看起來值為0. 這是一個未文檔化(並且可能不具可移植性)的行為. 賦值操作(前後都不能有空白) 因為=和-eq都可以用做條件測試操作, 所以不要與這裡的賦值操作相混淆. 注意: =既可以用做條件測試操作, 也可以用於賦值操作, 這需要視具體的上下文而定. 簡單的賦值操作舉例: [html] #!/bin/bash # 賦值 a=879 echo "The value of \"a\" is $a." # 使用'let'賦值 let a=16+5 echo "The value of \"a\" is now $a." # 在'for'迴圈中(事實上, 這是一種偽賦值): echo -n "Values of \"a\" in the loop are: " #這裡加上-n表示忽略string最後的換行操作,否則會換行 for a in 7 8 9 11 do echo -n "$a " done echo # 使用'read'命令進行賦值(這也是一種賦值的類型): echo -n "Enter \"a\": " read a #讀取輸入的值 echo "The value of \"a\" is now $a." exit 0 實驗結果:[html] root@ubuntu:~/resource/study/shell_study# ./value-test1 The value of "a" is 879. The value of "a" is now 21. Values of "a" in the loop are: 7 8 9 11 Enter "a": 121212 The value of "a" is now 121212. 再看一個稍微複雜一點的例子:[html] #!/bin/bash a=23 # 簡單的賦值 echo $a b=$a echo $b # 現在讓我們來點小變化(命令替換). a=`echo Hello!` # 把'echo'命令的結果傳給變數'a' echo $a a=`ls -l` # 把'ls -l'的結果賦值給'a' echo $a # 然而, 如果沒有引號的話將會刪除ls結果中多餘的tab和分行符號. echo echo "$a" # 如果加上引號的話, 那麼就會保留ls結果中的空白符. exit 0 看一看實驗結果:[html] root@ubuntu:~/resource/study/shell_study# chmod 777 value-test2 root@ubuntu:~/resource/study/shell_study# ./value-test2 23 23 Hello! total 48 -rwxrwxrwx 1 root root 663 2013-04-22 03:34 clear_log -rw-r--r-- 1 root root 354 2013-04-22 03:15 data-file -rwxrwxrwx 1 root root 404 2013-04-22 05:05 for_test -rwxrwxrwx 1 root root 345 2013-04-22 03:16 include_file -rwxrwxrwx 1 root root 831 2013-04-22 04:08 para_sub -rwxrwxrwx 1 root root 253 2013-04-22 00:35 show_self -rwxrwxrwx 1 root root 256 2013-04-22 04:41 test1 -rwxrwxrwx 1 root root 204 2013-04-22 04:50 test2 -rw-r--r-- 1 root root 59 2013-04-22 04:50 test-context -rwxrwxrwx 1 root root 1221 2013-04-23 22:33 value-test -rwxrwxrwx 1 root root 415 2013-04-23 22:51 value-test1 -rwxrwxrwx 1 root root 439 2013-04-23 22:57 value-test2 total 48 -rwxrwxrwx 1 root root 663 2013-04-22 03:34 clear_log -rw-r--r-- 1 root root 354 2013-04-22 03:15 data-file -rwxrwxrwx 1 root root 404 2013-04-22 05:05 for_test -rwxrwxrwx 1 root root 345 2013-04-22 03:16 include_file -rwxrwxrwx 1 root root 831 2013-04-22 04:08 para_sub -rwxrwxrwx 1 root root 253 2013-04-22 00:35 show_self -rwxrwxrwx 1 root root 256 2013-04-22 04:41 test1 -rwxrwxrwx 1 root root 204 2013-04-22 04:50 test2 -rw-r--r-- 1 root root 59 2013-04-22 04:50 test-context -rwxrwxrwx 1 root root 1221 2013-04-23 22:33 value-test -rwxrwxrwx 1 root root 415 2013-04-23 22:51 value-test1 -rwxrwxrwx 1 root root 439 2013-04-23 22:57 value-test2 Bash變數是不區分類型的不像其他程式語言一樣, Bash並不對變數區分"類型". 本質上, Bash變數都是字串. 但是依賴於具體的上下文, Bash也允許比較操作和整數操作. 其中的關鍵因素就是, 變數中的值是否只有數字. 下面看一下一個執行個體; [html] #!/bin/bash a=2334 # 整型. let "a += 1" echo "a = $a " # a = 2335 b=${a/23/BB} # 將"23"替換成"BB". echo "b = $b" # b = BB35 declare -i b # 即使使用declare命令也不會對此有任何協助. echo "b = $b" # b = BB35 let "b += 1" # BB35 + 1 = echo "b = $b" # b = 1 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 # null變數會如何呢? e="" echo "e = $e" # e = let "e += 1" # 算術操作允許一個null變數? echo "e = $e" # e = 1 # 如果沒有聲明變數會怎樣? echo "f = $f" # f = let "f += 1" # 算術操作能通過麼? echo "f = $f" # f = 1 # 所以說Bash中的變數都是不區分類型的. exit 0 看一看他是執行結果:[html] root@ubuntu:~/resource/study/shell_study# ./int-char a = 2335 b = BB35 b = BB35 b = 1 c = BB34 d = 2334 d = 2335 e = e = 1 f = f = 1 不區分變數的類型既是幸運的事情也是悲慘的事情. 它允許你在編寫指令碼的時候更加的靈活(但是也足夠把你搞暈!), 並且可以讓你能夠更容易的編寫代碼. 然而, 這也很容易產生錯誤, 並且讓你養成糟糕的編程習慣.這樣的話, 程式員就承擔了區分指令碼中變數類型的責任. Bash是不會為你區分變數類型的. 特殊的變數類型 局部變數 這種變數只有在代碼塊或者函數中(參見函數中的局部變數)才可見. 環境變數這種變數將影響使用者介面和shell的行為 在通常情況下, 每個進程都有自己的"環境", 這個環境是由一組變數組成的, 這些變數中存有進程可能需要引用的資訊. 在這種情況下, shell與一個一般的進程沒什麼區別. 每次當一個shell啟動時, 它都將建立適合於自己環境變數的shell變數. 更新或者添加一個新的環境變數的話, 這個shell都會立刻更新它自己的環境(譯者注: 換句話說, 更改或增加的變數會立即生效), 並且所有的shell子進程(即這個shell所執行的命令)都會繼承這個環境. (譯者注: 準確地說, 應該是後繼產生的子進程才會繼承Shell的新環境變數, 已經啟動並執行子進程並不會得到它的新環境變數). 分配給環境變數的空間是有限的. 建立太多環境變數, 或者給一個環境變數分配太多的空間都會引起錯誤. 如果一個指令碼要設定一個環境變數, 那麼需要將這些變數"export"出來, 也就是需要通知到指令碼本地的環境. 這是export命令的功能.一個指令碼只能夠export變數到這個指令碼所產生的子進程, 也就是說只能夠對這個指令碼所產生的命令和進程起作用. 如果指令碼是從命令列中調用的, 那麼這個指令碼所export的變數是不能影響命令列環境的. 也就是說, 子進程是不能夠export變數來影響產生自己的父進程的環境的. 位置參數從命令列傳遞到指令碼的參數: $0, $1, $2, $3 . . .$0就是指令檔自身的名字, $1 是第一個參數, $2是第二個參數, $3是第三個參數, 然後是第四個. $9之後的位置參數就必須用大括弧括起來了, 比如, ${10}, ${11}, ${12}.兩個比較特殊的變數$*和$@ 表示所有的位置參數. 還是看一個執行個體吧 [html] #!/bin/bash # 作為用例, 調用這個指令碼至少需要10個參數, 比如: # ./scriptname 1 2 3 4 5 6 7 8 9 10 MINPARAMS=10 echo "The name of this script is \"$0\"." echo "The name of this script is \"`basename $0`\"." if [ -n "$1" ] # 測試變數被引用. then echo "Parameter #1 is $1" # 需要引用才能夠轉義"#" fi if [ -n "$2" ] then echo "Parameter #2 is $2" fi if [ -n "$3" ] then echo "Parameter #3 is $3" fi if [ -n "${10}" ] # 大於$9的參數必須用{}括起來. then echo "Parameter #10 is ${10}" fi echo "-----------------------------------" echo "All the command-line parameters are: "$*"" if [ $# -lt "$MINPARAMS" ] then echo "This script needs at least $MINPARAMS command-line arguments!" fi exit 0 看看實驗結果:[html] root@ubuntu:~/resource/study/shell_study# ./args 1 2 3 The name of this script is "./args". The name of this script is "args". Parameter #1 is 1 Parameter #2 is 2 Parameter #3 is 3 ----------------------------------- All the command-line parameters are: 1 2 3 This script needs at least 10 command-line arguments! root@ubuntu:~/resource/study/shell_study# ./args 1 2 3 4 5 6 7 8 9 10 11 The name of this script is "./args". The name of this script is "args". Parameter #1 is 1 Parameter #2 is 2 Parameter #3 is 3 Parameter #10 is 10 ----------------------------------- All the command-line parameters are: 1 2 3 4 5 6 7 8 9 10 11 {}標記法提供了一種提取從命令列傳遞到指令碼的最後一個位置參數的簡單辦法一些指令碼可能會依賴於使用不同的調用名字, 來表現出不同的行為. 如果想要達到這種目的, 一般都需要在指令碼中檢查$0. 因為指令碼只能夠有一個真正的檔案名稱, 如果要產生多個名字, 必須使用符號連結. 看一下shift命令的使用執行個體: [html] #!/bin/bash # 使用'shift'來逐步存取所有的位置參數. 給指令碼命個名, 比如shft,然後給指令碼傳遞一些位置參數, 比如: ./shft a b c def 23 skidoo until [ -z "$1" ] # 直到所有的位置參數都被存取完... do echo -n "$1 " shift done echo exit 0 查看實驗結果:[html] root@ubuntu:~/resource/study/shell_study# ./shift d df lsjf sldjf d df lsjf sldjf