本文的主要內容:1、數組
2、命令組合3、進程替換
4、陷阱機制5、常見錯誤與防錯
一、數組Bash 中的數組僅限制為單一維度。對數組的支持第一次出現在 bash 版本2中。
1.創建一個數組$ a[1]=foo
$ echo ${a[1]}
foo
其中第一個命令把數組 a 的元素1賦值為 “foo”,第二個命令顯示存儲在元素1中的值。在第二個命令中使用花括號是必需的, 以便防止 shell 試圖對數組元素名執行路徑名展開操作
也可以用 declare 命令創建一個數組:
$ declare -a a
使用 -a 選項,declare 命令的這個例子創建了數組 a
2.數組賦值有兩種方式可以給數組賦值。
單個值賦值使用以下語法:name[subscript]=value
多個值賦值使用下面的語法:name=(value1 value2 ...)
例如:
$ days=(Sun Mon Tue Wed Thu Fri Sat)
$ days=([0]=Sun [1]=Mon [2]=Tue [3]=Wed [4]=Thu [5]=Fri [6]=Sat)
3.輸出整個數組的內容下標 * 和 @ 可以被用來訪問數組中的每一個元素
例如:
$ animals=("a dog" "a cat" "a fish")
$ for i in ${animals[*]}; do echo $i; done
a
dog
a
cat
a
fish
$ for i in ${animals[@]}; do echo $i; done
a
dog
a
cat
a
fish
$ for i in "${animals[*]}"; do echo $i; done
a dog a cat a fish
$ for i in "${animals[@]}"; do echo $i; done
a dog
a cat
a fish
4.確定數組元素個數例如:
$ a[100]=foo
$ echo ${#a[@]} #數組元素個數
1
$ echo ${#a[100]} #第100元素的長度
3
盡管我們把字符串賦值給數組元素100,但bash僅僅報告數組中有一個元素,這不同於一些其它語言
5.找到數組使用的下標因為 bash 允許賦值的數組下標包含“間隔”,確定哪個元素真正存在可以使用以下形式的參數展開:
${!array[*]}
${!array[@]}
例如:
$ foo=([2]=a [4]=b [6]=c)
$ for i in "${foo[@]}"; do echo $i; done
a
b
c
$ for i in "${!foo[@]}"; do echo $i; done
2
4
6
6.在數組末尾添加元素使用 += 賦值運算符
例如:
$ foo=(a b c)
$ echo ${foo[@]}
a b c
$ foo+=(d e f)
$ echo ${foo[@]}
a b c d e f
7.數組排序Shell 沒有直接排序的方法,但可通過管道給sort實現
例如:
#!/bin/bash
# array-sort : Sort an array
a=(f e d c b a)
echo "Original array: ${a[@]}"
a_sorted=($(for i in "${a[@]}"; do echo $i; done | sort))
echo "Sorted array: ${a_sorted[@]}"
8.刪除數組刪除一個數組,使用 unset 命令:
$ foo=(a b c d e f)
$ unset foo
亦可用unset命令刪除單個的數組元素:
$ foo=(a b c d e f)
$ unset 'foo[2]'
注:數組下標開始於0,數組元素用引號引起來可防止 shell執行路徑名展開操作。
給一個數組賦空值不會清空數組內容:
$ foo=(a b c d e f)
$ foo=
$ echo ${foo[@]}
b c d e f
引用一個不帶下標的數組變量,則指的是數組元素0:
$ foo=(a b c d e f)
$ echo ${foo[@]}
a b c d e f
$ foo=A
$ echo ${foo[@]}
A b c d e f
9.關聯數組例如創建顏色數組
declare -A colors
colors["red"]="#ff0000"
colors["green"]="#00ff00"
colors["blue"]="#0000ff"
訪問關聯數組元素:
echo ${colors["blue"]}
二、命令組合用一個 group 命令,或者用一個子 shell可以把命令組合在一起
組命令:{ command1; command2; [command3; ...] }
注:花括號與命令之間必須有一個空格,並且最後一個命令必須用一個分號或者一個換行符終止
子 shell:(command1; command2; [command3;...])
例如:
ls -l > output.txt echo "Listing of foo.txt" >> output.txt cat foo.txt >> output.txt可以用命令組合改為:
{ ls -l; echo "Listing of foo.txt"; cat foo.txt; } > output.txt或
(ls -l; echo "Listing of foo.txt"; cat foo.txt) > output.txt三、進程替換
1.當子 shell 退出時,環境副本會消失,所以在子 shell 環境(包括變量賦值)中的任何更改也會消失,例如:
echo "foo" | read
echo $REPLY
因為管道線中的命令總是在子 shell 中執行,所以該REPLY變量的內容總是為空
2.進程替換有兩種表達方式:
一種適用於產生標准輸出的進程:<(list)
另一種適用於接受標准輸入的進程:>(list)
其中list 是一串命令列表
3.解決上面的 read 命令問題,可用進程替換,例如:
read < <(echo "foo")
echo $REPLY
4.進程替換允許我們把一個子 shell 的輸出結果當作一個用於重定向的普通文件,檢驗如下:
$ echo <(echo "foo")
/dev/fd/63
使用 echo 命令,查看展開結果,我們看到子 shell 的輸出結果,由一個名為 /dev/fd/63 的文件提供
5.例子:
#!/bin/bash # pro-sub : demo of process substitution while read attr links owner group size date time filename; do cat <<- EOF Filename: $filename Size: $size Owner: $owner Group: $group Modified: $date $time Links: $links Attributes: $attr EOF done < <(ls -l | tail -n +2)這個循環對目錄列表的每一個條目執行 read 命令。列表本身產生於該腳本的最後一行代碼。這一行代碼把從進程替換得到的輸出 重定向到這個循環的標准輸入。這個包含在管道線中的
tail 命令,是為了消除列表的第一行文本,這行文本是多余的。
四、陷阱(trap)機制1.trap語法如下:
trap argument signal [signal...]
其中argument是一個字符串,它被讀取並作為一個命令,signal 是一個信號的說明,它會觸發執行所要解釋的命令
2.例子:
#!/bin/bash # trap-demo : simple signal handling demo trap "echo 'I am ignoring you.'" SIGINT SIGTERM for i in {1..5}; do echo "Iteration $i of 5" sleep 5 done
此腳本定義一個陷阱,當腳本運行時每當接受到一個 SIGINT 或 SIGTERM 信號時,就會執行一個 echo 命令
五、常見錯誤與防錯1.語法錯誤
丟失引號:
......
if [ $number = 1 ]; then
echo "Number is equal to 1.
else
......
其中echo語句後面缺少一個引號
丟失或意外的標記:
......
if [ $number = 1 ] then
echo "Number is equal to 1."
else
......
其中if測試語句後面缺少一個分號
預料不到的展開
......
number=
if [ $number = 1 ]; then
......
其中當number展開後為[ = 1 ],若為測試語句的第一個參數添加雙引號[ "$number" = 1 ]可更正此問題,此時展開後為[ "" = 1 ]
2.防錯編程:驗證假設例如:
cd $dir_name rm *若dir_name所指的目錄不存在則會刪除當前工作目錄中的所有文件
對此可將命令改為:
[[ -d $dir_name ]] && cd $dir_name && rm *通常,當某種情況(比如上述問題)發生的時候,最好是終止腳本執行,並對這種情況提示錯誤信息:
if [[ -d $dir_name ]]; then if cd $dir_name; then rm * else echo "cannot cd to '$dir_name'" >&2 exit 1 fi else echo "no such directory: '$dir_name'" >&2 exit 1 fi3.其他防錯技巧
驗證輸入
如:[[ $REPLY =~ ^[0-3]$ ]]
測試命令
如:echo rm *
將 rm 命令及其展開的參數列表打印出來,而不是執行實際的rm命令語句
使用echo輸出變量內容
。。。
參考:《The Linux Command Line》