shell入門教程(1)-shell基礎 - justkk的專欄 - 部落格頻道 - CSDN.NET
http://blog.csdn.net/justkk/article/details/43795131
shell入門教程(2)-變數和參數 - justkk的專欄 - 部落格頻道 - CSDN.NET
http://blog.csdn.net/justkk/article/details/44081993
shell入門教程(3)-命令編輯 - justkk的專欄 - 部落格頻道 - CSDN.NET
http://blog.csdn.net/justkk/article/details/44617445
shell入門教程(4)-作業控制 - justkk的專欄 - 部落格頻道 - CSDN.NET
http://blog.csdn.net/justkk/article/details/46801163
SHELL入門教程(5)-算術運算 - justkk的專欄 - 部落格頻道 - CSDN.NET
http://blog.csdn.net/justkk/article/details/47025297
SHELL入門教程(6)-環境 - justkk的專欄 - 部落格頻道 - CSDN.NET
http://blog.csdn.net/justkk/article/details/47025321
SHELL入門教程(7)-編寫指令碼 - justkk的專欄 - 部落格頻道 - CSDN.NET
http://blog.csdn.net/justkk/article/details/47025397
1、執行指令碼
SHELL也是一個高層程式設計語言,SHELL程式通常稱為指令碼,是解釋執行的,不需要編譯。
指令碼的執行需要讀取r與執行x許可權,可以通過chmod命令添加相應的許可權,ls -l查看許可權。
ls -l 0.sh
-rwxr-xr-x. 1 root root 10 Jul 8 14:59 0.sh
可以直接通過指令碼名稱執行,如:0.sh,此時需要讀取與執行許可權。
也可以使用bash執行,如:bash 0.sh,此時只需要讀取許可權。
通常,SHELL指令碼是在一個單獨環境中執行:
1、當前SHELL中的變數需要export之後才能在指令碼中使用
2、另外,指令碼不會改變當前SHELL環境。
2、位置參數
位置參數是一組特殊變數,用來跟蹤指令碼的參數,其名稱只包含數字,如:
$0 表示指令碼名稱本身,剩餘的$1 $2 ..依次表示指令碼的參數
可以使用下面的指令碼驗證:
echo "Script name: $0"
echo "Number of args passed: $#"
echo "Arguments passed: $*"
echo "Arg 1=$1,Arg 2=$2, Arg 3=$3"
儲存為 0.sh,執行./0.sh a b c
特殊的變數:
$# 表示參數數目,$*與 $@ 表示所有的參數。
$* 與 $@的區別:$* 把所有參數作為一個整體,而$@表示分離的個體。不帶雙引號時,兩者效果相同。
位置參數不能直接使用var=value的方式修改,可以使用shift 命令。
shift 命令依次向左移動所有的參數,每個參數替代目標位置上的參數,同時參數的數目相應減少。
預設移動一個,可以指定參數,表示移動的數目,如 shift 2
可以使用下面的指令碼驗證:
echo "Number of args passed: $#"
echo "Arguments passed: $*"
echo "Arg 1=$1,Arg 2=$2, Arg 3=$3"
shift
echo "Number of args passed: $#"
echo "Arguments passed: $*"
echo "Arg 1=$1,Arg 2=$2, Arg 3=$3"
儲存為 0.sh,執行./0.sh a b c
3、exit
exit 命令退出指令碼的執行,後續的命令不再執行。
可以附帶一個參數,用來表示整個指令碼的退出狀態,即執行結果。
如:
echo "over"
exit 1
儲存為 0.sh,執行./0.sh
之後在 SHELL 中查看指令碼的退出狀態,echo $?
4、[[..]] 命令
這個命令用來執行條件判斷,可以檢查檔案屬性、字串、模式、整數等。
格式為 [[ expression ]],注意[[ 後面以及 ]] 前面都需要空格,操作符兩邊也需要空格。樣本:
[[ $a = 3 ]] && echo "a is 3"
c=hi; [[ $c = h* ]] && echo "begin with h"
a=4; [[ $a = +([0-9]) ]] && echo "a number"
字串操作符
-n string true if length of string is not zero
-o option true if option is set
-z string true if length of string is zero
string1 = string2 true if string1 is equal to string2
string1 != string2 true if string1 is not equal to string2
string = pattern true if string matches pattern
string != pattern true if string does not match pattern
string1 < string2 true if string1 less than string2
string1 > string2 true if string1 greater than string2
具體用法參見 man test
注意整數的比較,使用-gt -lt等,不能使用大於或小於,那是用來比較字串的
[[ 13 > 2 ]] && echo "13>2"
[[ 13 -gt 2 ]] && echo "13 greater than 2"
其實整數的比較可以使用((..))命令,更方便,其中的變數不用添加$,也不需要空格,如:
a=13;((a>2))&&echo ">2"
一點注意,兩個整數的相等比較,在((..))內部需要使用==,而不是=。單個等號的含義是賦值。
在[[..]]內部可以使用==或單個等號來比較。
與C語言類似,!表示邏輯 NOT。&&表示並且,||表示或者。()用來改變運算式優先順序。
(((3+2)*4==20))&&echo "20"
test或[..]也可以用來執行條件判斷,他們同樣是SHELL的內建命令。如:
test 1 -eq 1 && echo "ok"
[ 1 -eq 1 ] && echo "ok"
與他們相比,推薦使用[[..]]
總結:
1、整數的比較操作使用((..)),其他的比較操作使用[[..]]
2、使用雙等號==判斷兩個運算元是否相等
5、控制命令 • case 執行多個分支檢測,如:
case $1 in
a) echo "a";;
b) echo "b";;
*) echo "other";;
esac • for 命令執行迴圈
for i in 1 2 3
do
echo $i
done
或者,此時迴圈變數依次從所有的位置參數取值
for i
do
echo $i
done
或者,
for((i=1;i<10;i++))
do
echo $i
done • if ,如:
a=7
if ((a>10));then
echo "a>10"
elif ((a>5));then
echo "a>5"
else
echo "a<=5"
fi • while ,如:
a=1
while((a<10))
do
echo $a
((a++))
done • until ,如:
a=1
until((a==10))
do
echo $a
((a++))
done • break 跳出迴圈, continue 繼續迴圈
其參數指定迴圈的層次,預設為1
如:break 2 跳出2層迴圈
• select ,用來顯示一個簡單的菜單,並等待使用者的選擇,如:
select i in Choice-A Choice-B Choice-C
do
echo "You picked selection $REPLY: $i"
done
觀察輸出結果,顯示了SHELL的第三個命令列提示符PS3,其預設值是#?,可以修改並查看效果。
順便說一下最後一個命令列提示符PS4,這是跟蹤調試提示符,預設值是+,當開啟SHELL的跟蹤選項時,每個執行的命令及其參數都會先行顯示,行首添加PS4 的值。 • 關於注釋
# 之後直到行尾的內容都作為注釋,而不會被SHELL解釋執行。
特別注意,指令碼第一行的頂頭的#! 不是注釋,它後面可以指定一個執行程式,表示整個指令碼由那個執行程式解釋執行。如:
#!/usr/bin/awk -f
{print $0}
6、輸入輸出命令 • echo 輸出資訊,支援逸出字元
\a bell character
\b backspace
\c line without ending newline (remaining arguments ignored)
\f formfeed
\n newline
\r return
\t tab
\v vertical tab
\\ backslash
\0x 8-bit character whose ASCII code is the 1-, 2-, or 3-digit octal number x
注意,使用逸出字元時需要使用-e選項,如:
echo -e "\044"
echo -e "a\tb\ncd"
• exec I/O 重新導向,使用檔案描述符 0-9 ,如:
exec 5>&1 # 複製檔案描述符,此時5等價於1,都對應螢幕
echo a>&5 # 寫入描述符5,實際輸出到螢幕
exec 1>ff.out # 重新導向描述符1,指向檔案ff.out
echo b # 輸出到檔案ff.out
exec 1>&5 # 再次重新導向描述符1,指向描述符5,對應螢幕
echo c # 輸出到螢幕
exec 1>&- # 關閉描述符1
echo d # 報錯,因為輸出已關閉
• read 讀取輸入內容,存入變數,如:
read a # 等待鍵盤輸入,輸入內容放入變數a
read a b # 等待鍵盤輸入,拆分後放入變數a,b,分隔字元通常是空白符,如空格、<TAB> • IFS 變數,用以指定輸入內容的分隔字元,如: IFS=,
之後輸入內容採用逗號分隔,read a b,如果輸入1,2,那麼變數a和b分別取值1和2。 • read 命令預設從標準輸入(即描述符 0 )讀取內容,可以通過 -u 選項指定從其他描述符讀取,如:
exec 4<ff.out
read -u4 b • REPLY 變數
如果read命令沒有指定任何變數,讀取內容將放入變數REPLY,如:
read; echo $REPLY
• read 命令的一個 陷阱 ,查看下面的情境:
unset b c
A="3 4"
echo $A|read b c
echo $b,$c
希望變數b和c分別取值3和4,實際驗證結果:變數b和c什麼也沒有。
究其原因,read命令是在子SHELL中執行的,雖然在子SHELL中讀到了3和4,但是不會影響當前SHELL。
修改:
unset b c
A="3 4"
read b c <<!
$A
!
echo $b,$c
8、其他 • . 命令, source 命令,兩者等價,在當前 SHELL 中執行參數指定的指令碼, 改變當前的 SHELL 環境
通常用來讀取並執行一個環境定義檔案,假定檔案0.sh的內容如下:
A=3
B=4
比較兩種執行方式:./0.sh 與 . ./0.sh • 函數,定義形式如下,其中關鍵字 function 可以省略:
function aa()
{
echo aa
}
函數定義之後,其調用方式與參數傳遞方式與普通命令類似,同樣可以使用$?檢查其退出狀態。
aa()
{
echo hh
return 1
}
aa # 調用時可以給函數傳遞參數,函數內部需要使用位置參數訪問
echo $?
• 預設情況下當前 SHELL 中定義的函數在子 SHELL 中不可用,需要匯出: export -f aa • 預設情況下,函數中的變數和調用者是共用的
調用前定義的變數可以在函數中使用,函數中定義的變數在調用結束後依然可見,函數內部定義局部變數時可以使用 local 關鍵字。
A=1
function aa
{
local A=3
B=2
echo "in function: $A,$B"
}
aa
echo $A,$B • 查看已經定義的函數
使用typeset -F -p 或 typeset -f -p,前者只顯示函數名稱,後者同時顯示函數的定義。
• trap 命令,用來捕獲訊號,並執行對應的動作,如:
trap 'echo nono' 2 # 捕獲中斷訊號
trap "" 2 # 忽略中斷訊號
trap 2 # 恢複中斷訊號的預設處理
特殊的訊號0,表示指令碼退出。可以捕獲這個訊號,在指令碼退出時執行一些清理動作。
trap 'echo over' 0
..
• 調試指令碼
幾個有用的選項:
-n 唯讀入指令碼,並不實際執行,只檢查文法
-v 讀入指令碼時顯示讀入的程式碼
-x 執行時顯示每個命令及其參數
如:sh -x 0.sh
可以定製 -x 選項顯示的提示符,如:export PS4='[$LINENO] ‘
之後將顯示每個命令所在的行號
trap 命令也可以用來調試指令碼,使用特殊的訊號,如:DEBUG、ERR
trap 'echo error at line $LINENO' ERR
trap 'echo debug line=$LINENO' DEBUG
每