1.Shell腳本
1.1 格式
首行 #!/bin/bash
指定解釋器
1.2 注釋
'#'開頭的行,'#!'是例外
此外,# 是特殊字符,可以出現在一些參數代換結構和在數值常量表達式中,具有特殊含義,而不會開啟一個注釋。‘#’也不會開啟一個注釋。
1.3 函數
function funname(){…}
或者
funname()
{
statements;
}
只需要使用函數名就可以調用某個函數:funname
參數可以傳遞給函數,使用方法就好像函數是個新腳本一樣:
funname arg1 arg2...; #傳遞參數
在函數中使用傳入的參數:$1 第一個參數;$@ 所有參數。
其中:"$@"被擴展成"$1""$2""$3";
"$*"被擴展成"$1c$2c$3",即一個字符串。c為IFS的第一個字符。
有時我們需要知道命令或者函數的執行狀態,用$?可以查看前一個命令的返回值,如果命令成功退出,那么退出狀態為0,否則非0。
1.4 正文部分
流程控制+命令
1.5 執行:修改權限
轉為可執行程序
chmod +x ./test.sh #使腳本具有執行權限
./test.sh #執行腳本
1.6 流程控制
條件語句
if :
if condition
then
command1
command2
...
commandN
fi
if `ps -ef | grep ssh`;
then
echo hello;
fi
if else-if else :
if condition1
then
command1
elif condition2
command2
else
commandN
fi
循環語句
for :
for var in item1 item2 ... itemN
do
command1
command2
...
commandN
done
for var in item1 item2 ... itemN; do command1; command2… done;
while :
i=1;total=0;
while [ $i -le 10 ]
do
let total+=i
let i++
echo $total,$i
done
i=1; total=0;
while((i<=10))
do
((total+=i, i++))
echo $total,$i
done
case語句: case語句可以用戶處理自定義參數。
case $num in
1) echo "January";; #雙分號結束
2) echo "Feburary";;
5) echo "may" #每個case可以有多條命令
echo "sdfd"
echo "sdf";; #但最后一條命令一定是雙分號結束
*) echo "not correct input";; #*)是其他值、default的意思
esac
1.7 while read line
while read line; do something ; done
1.8 參數處理
a) "$*"將所有的參數解釋成一個字符串,而"$@"是一個參數數組。
b) Shell內建函數getopts “:a:bc” opt
主要變量:
$OPTIND : 存儲所處理的選項在參數列表中的位置
$OPTARG : 存儲相應選項所帶的參數
例子:
while getopts ":a:b:cef" opt
do
case $opt in
a)echo "the $OPTIND has arg:$OPTARG";;#$OPTIND=3
b)echo "the b has arg:$OPTARG";;
c | e | f)echo "the $opt has no arg";;
\?)echo "the $opt is invalid param";;
esac
done
c) shift n 將位置命令左移n個
1.9 條件判斷
條件判斷應該放進方括號里,且方括號兩邊都應該留有空格。 [ ]
a) 字符串判斷
字符串比較時,最好用雙中括號,因為有時候采用單中括號會產生錯誤,所以最好避開它們。[[ $str1 = $str2 ]]
= 當兩個串有相同內容、長度時為真
!= 當串str1和str2不等時為真
-n 當串的長度大于0時為真(串非空)
-z 當串的長度為0時為真(空串)
b) 數值判斷
-eq 兩數相等為真
-ne 兩數不等為真
-gt int1大于int2為真
-ge int1大于等于int2為真
-lt int1小于int2為真
-le int1小于等于int2為真
c) 文件判斷
-e file 若文件存在,則為真
-d file 若文件存在且是一個目錄,則為真
-b file 若文件存在且是一個塊特殊文件,則為真
-c file 若文件存在且是一個字符特殊文件,則為真
-f file 若文件存在且是一個規則文件,則為真
-g file 若文件存在且設置了SGID位的值,則為真
-h file 若文件存在且為一個符合鏈接,則為真
-k file 若文件存在且設置了"sticky"位的值
-p file 若文件存在且為一已命名管道,則為真
-r file 若文件存在且可讀,則為真
-s file 若文件存在且其大小大于零,則為真
-u file 若文件存在且設置了SUID位,則為真
-w file 若文件存在且可寫,則為真
-x file 若文件存在且可執行,則為真
-o file 若文件存在且被有效用戶ID所擁有,則為真
d) 邏輯判斷
! 非
-a 與 &&
-o 或 ||
if [ $v –ne 0 –a $v –lt 2 ] 等價 if [ $v –ne 0 ] && [ $v –lt 2 ]
if [ $v –ne 0 –o $v –lt 2 ] 等價 if [ $v –ne 0 ] || [ $v –lt 2 ]
條件判斷部分可能會變得很長,一個優化的小技巧是利用&&和||運算符。
if condition
then
command1
else
command2
fi
[ condition ] && command1 || command2
這樣就用一行代替了上面的5行而實現的功能完全相同。
如果命令有多個,可以用{}括起來,當做一個命令塊。
這樣可以使判斷語句變得非常簡潔。
1.10 &&、||
cmd1 && cmd2
表示,當cmd1執行成功后,就執行cmd2,否則不執行。
cmd1 || cmd2
表示,當cmd1執行失敗后,就執行cmd2,否則不執行。
2.變量
2.1 系統變量
$n 該變量與腳本被激活時所帶的參數相對應。n是正整數,與參數位置相對應($1,$2...)
$? 前一個命令執行后的退出狀
$# 提供腳本的參數號
$* 所有這些參數都被雙引號引住。若一個腳本接收兩個參數,$*等于$1$2
$0 正在被執行命令的名字。對于shell腳本而言,這是被激活命令的路徑
$@ 所有這些參數都分別被雙引號引住。若一個腳本接收到兩個參數,$@等價于$1$2
$$ 當前shell的進程號。對于shell腳本,這是其正在執行時的進程ID
$! 前一個后臺命令的進程號
2.2 普通變量
- 賦值:var=value
獲取字符串的長度。len=${#var}
- 數值運算:let
let命令后面的變量不用帶$,如:
nu=10;
let nu+=10; #nu=20
但這個命令不能進行浮點數的運算。 - 浮點數運算:bc
echo "4 * 0.6" | bc
bc是一個強大的計算器,還可以進項如下操作:
設定小數精度,scale=2,eg:echo "scale=2;3 / 8" | bc
#.37 這是bc的特性,小于0的數,是不顯示小數點前的0的。
進制轉換。用ibase設定輸入數字的進制,obase設定輸出數字的進制。
no=10
echo "obase=2;ibase=10;$no" | bc #1010
計算平方以及平方根。
echo "10^4" | bc #1000 平方
echo "sqrt(100)" | bc #10 平方根
2.3 IFS
全稱是Internal Field Separtor,內部分隔符。
Shell 的環境變量分為 set, env 兩種,其中 set 變量可以通過 export 工具導入到 env 變量中。其中,set 是顯示設置shell變量,僅在本 shell 中有效;env 是顯示設置用戶環境變量 ,僅在當前會話中有效。換句話說,set 變量里包含了 env 變量,但 set 變量不一定都是 env 變量。這兩種變量不同之處在于變量的作用域不同。顯然,env 變量的作用域要大些,它可以在 subshell 中使用。
而 IFS 是一種 set 變量,當 shell 處理"命令替換"和"參數替換"時,shell 根據 IFS 的值,默認是 space, tab, newline 來拆解讀入的變量,然后對特殊字符進行處理,最后重新組合賦值給該變量。
eg:
$ cat test.txt
1
2
3
$ out=$(cat test.txt)
$ echo $out
1 2 3 #shell將(cat test.txt)的結果拆解,并用默認的分隔符(空格)重新組合,賦值給out,因此echo $out的結果不包含換行。
如果要保留cat test.txt中的換行符,一般情況下要做兩步:
1是,設定IFS為換行:IFS='\n'
2是,將$(cat test.txt)用雙引號引起來,表示不用
若指定IFS為換行符。
2.4 UID
特殊的環境變量,如果UID=0,表示當前以root用戶運行腳本。否則不是root
3.自增
Linux Shell中寫循環時,常常要用到變量的自增,現在總結一下整型變量自增的方法。
1) i=`expr $i + 1`;
2) let i+=1;
3) ((i++)); #雙括號結構
http://www.cnblogs.com/chengmo/archive/2010/10/19/1855577.html
4) i=$[$i+1];
5) i=$(( $i + 1 ))
4.雙括號結構(())
雙括號結構是對shell中算數及賦值運算的擴展。
語法:
((表達式1,表達式2…))
特點:
- 在雙括號結構中,所有表達式可以像c語言一樣,如:a++,b--等。
- 在雙括號結構中,所有變量可以不加入:“$”符號前綴。
- 雙括號可以進行邏輯運算,四則運算.eg. echo $((a>1?2:3));注意四則運算中仍然不支持浮點數運算
- 支持多個表達式運算,各個表達式之間用“,”分開. eg:((a+1,b++,c++))
- 雙括號結構 擴展了for,while,if條件測試運算
5.數組
- 取數組長度 – '#'
arr=(1 2 3 4 5)
len=${#arr[@]}
- 打印特定索引的數組元素
echo ${arr[2]} #2
- 打印出數組中的所有值-'*'、'@'
echo ${arr[*]}
echo ${arr[@]}
6.關聯數組
在關聯數組中,可以用任意的文本作為數組索引。先聲明才能使用
- 聲明一個關聯數組。
declare –A ass_array
- 賦值:
a) ass_array=([index1]=val1 [index2]=val2)
b) ass_array[index1]=val1
ass_array[index2]=val2
echo ${ass_array[index1]}
- 列出數組索引:
echo ${!ass_array[@]}
7.臨時文件或目錄
在shell腳本中經常要保存臨時的數據,如果使用認為創建臨時文件用戶保存臨時數據,則有可能出現重名的情況,導致覆蓋原來的數據。
mktemp prefile.xxx 創建以prefile開頭的隨機文件文件,并返回文件名,指定前綴時必須包含至少3個xxx。
主要參數:
-d : 創建一個目錄,dirname=mktemp -d
-u : 僅生成隨機文件名,但不創建實際的文件或目錄,tmpfile=mktemp -u