這些必備的Linux shell知識你都掌握了嗎
前言
在linux下使用shell編程常常能夠極大簡化我們的工作。而下面這些必備的知識你是否都掌握了呢?
入參和默認變量
對于shell腳本而言,有些內容是專門用于處理參數的,它們都有特定的含義,例如:
- /home/shouwang/test.sh para1 para2 para3
- $0 $1 $2 $3
- 腳本名 ***個參數 第三個參數
其中$0代表了執行的腳本名,$1,$2分別代表了***個,第二個參數。除此之外,還有一些其他的默認變量,例如:
- # 代表腳本后面跟的參數個數,前面的例子中有3個參數
- $@ 代表了所有參數,并且可以被遍歷
- $* 代表了所有參數,且作為整體,和$*很像,但是有區別
- $$ 代表了當前腳本的進程ID
- $? 代表了上一條命令的退出狀態
變量
給變量賦值,使用等號即可,但是等號兩邊千萬不要有空格,等號右邊有空格的字符串也必須用引號引起來:
- para1="hello world" #字符串直接賦給變量para1
unset用于取消變量。例如:
- unset para1
如何使用變量呢?使用變量時,需要在變量前加$,例如要打印前面para1的內容:
- echo "para1 is $para1"
- #將會輸出 para1 is hello world
或者變量名兩邊添加大括號:
- echo "para1 is ${para1}!"
- #將會輸出 para1 is hello world!
命令執行
在shell中執行命令通常只需要像在終端一樣執行命令即可,不過,如果想要命令結果打印出來的時候,這樣的方式就行不通了。因此,shell的命令方式常有:
- a=`ls` #`是左上角~鍵,不是單引號
或者使用$,后面括號內是執行的命令:
- echo "current path is $(pwd)" #
另外,前面兩種方式對于計算表達式也是行不通的,而要采取下面的方式:
- echo "1+1=$((1+1))" #打印:1+1=2
即$后面用兩重括號將要計算的表達式包裹起來。
那如果要執行的命令存儲在變量中呢?前面的方法都不可行了,當然括號內的內容被當成命令執行還是成立的。要使用下面的方式,例如:
- a="ls"
- echo "$($a)"
但是如果字符串時多條命令的時候,上面的方式又不可行了,而要采用下面的方式:
- a="ls;pwd"
- echo "$(eval $a)"v
這是使用了eval,將a的內容都作為命令來執行。
條件分支
一般說明,如果命令執行成功,則其返回值為0,否則為非0,因此,可以通過下面的方式判斷上條命令的執行結果:
- if [ $? -eq 0 ]
- then
- echo "success"
- elif [ $? -eq 1 ]
- then
- echo "failed,code is 1"
- else
- echo "other code"
- fi
case語句使用方法如下:
- name="aa"
- case $name in
- "aa")
- echo "name is $name"
- ;;
- "")
- echo "name is empty"
- ;;
- "bb")
- echo "name is $name"
- ;;
- *)
- echo "other name"
- ;;
- esac
初學者特別需要注意以下幾點:
- []前面要有空格,它里面是邏輯表達式
- if elif后面要跟then,然后才是要執行的語句
- 如果想打印上一條命令的執行結果,***的做法是將 $?賦給一個變量,因為一旦執行了一條命令,$?的值就可能會變。
- case每個分支***以兩個分號結尾,***是case反過來寫,即esac。
多個條件如何使用呢,兩種方式,方式一:
- if [ 10 -gt 5 -o 10 -gt 4 ];then
- echo "10>5 or 10 >4"
- fi
方式二:
- if [ 10 -gt 5 ] || [ 10 -gt 4 ];then
- echo "10>5 or 10 >4"
- fi
其中-o或者||表示或。這里也有一些常見的條件判定。
總結如下:
- o or 或者,同||
- -a and 與,同&&
- ! 非
整數判斷:
- -eq 兩數是否相等
- -ne 兩數是否不等
- -gt 前者是否大于后者(greater then)
- -lt 前面是否小于后者(less than)
- -ge 前者是否大于等于后者(greater then or equal)
- -le 前者是否小于等于后者(less than or equal)
字符串判斷str1 exp str2:
- -z "$str1" str1是否為空字符串
- -n "$str1" str1是否不是空字符串
- "$str1" == "$str2" str1是否與str2相等
- "$str1" != "$str2" str1是否與str2不等
- "$str1" =~ "str2" str1是否包含str2
特別注意,字符串變量***用引號引起來,因為一旦字符串中有空格,這個表達式就錯了,有興趣的可以嘗試當str1="hello world",而str2="hello"的時候進行比較。
文件目錄判斷:filename
- -f $filename 是否為文件
- -e $filename 是否存在
- -d $filename 是否為目錄
- -s $filename 文件存在且不為空
- ! -s $filename 文件是否為空
循環
循環形式一,和Python的for in很像:
- #遍歷輸出腳本的參數
- for i in $@; do
- echo $i
- done
循環形式二,和C語言風格很像:
- for ((i = 0 ; i < 10 ; i++)); do
- echo $i
- done
循環打印0到9。
循環形式三:
- for i in {1..5}; do
- echo "Welcome $i"
- done
循環打印1到5。
循環方式四:
- while [ "$ans" != "yes" ]
- do
- read -p "please input yes to exit loop:" ans
- done
只有當輸入yes時,循環才會退出。即條件滿足時,就進行循環。
循環方式五:
- ans=yes
- until [ $ans != "yes" ]
- do
- read -p "please input yes to exit loop:" ans
- done
這里表示,只有當ans不是yes時,循環就終止。
循環方式六:
- for i in {5..15..3}; do
- echo "number is $i"
- done
每隔5打印一次,即打印5,8,11,14。
函數
定義函數方式如下:
- myfunc()
- {
- echo "hello world $1"
- }
或者:
- function myfunc()
- {
- echo "hello world $1"
- }
函數調用:
- para1="shouwang"
- myfunc $para1
返回值
通常函數的return返回值只支持0-255,因此想要獲得返回值,可以通過下面的方式。
- function myfunc() {
- local myresult='some value'
- echo $myresult
- }
- val=$(myfunc) #val的值為some value
通過return的方式適用于判斷函數的執行是否成功:
- function myfunc() {
- #do something
- return 0
- }
- if myfunc;then
- echo "success"
- else
- echo "failed"
- fi
注釋
shell通過#來注釋一行內容,前面我們已經看到過了:
- #!/bin/bash
- # 這是一行注釋
- :'
- 這是
- 多行
- 注釋
- '
- ls
- :<<EOF
- 這也可以
- 達到
- 多行注釋
- 的目的
- EOF
日志保存
腳本執行后免不了要記錄日志,最常用的方法就是重定向。以下面的腳本為例:
- #!/bin/bash
- #test.sh
- lll #這個命令是沒有的,因此會報錯
- date
方式一,將標準輸出保存到文件中,打印標準錯誤:
- ./test.sh > log.dat
這種情況下,如果命令執行出錯,錯誤將會打印到控制臺。所以如果你在程序中調用,這樣將不會講錯誤信息保存在日志中。
方式二,標準輸出和標準錯誤都保存到日志文件中:
- ./test.sh > log.dat 2>&1
2>&1的含義可以參考《如何理解linuxshell中的2>&1》
方式三,保存日志文件的同時,也輸出到控制臺:
- ./test.sh |tee log.dat
腳本執行
最常見的執行方式前面已經看到了:
- ./test.sh
其它執行方式:
- sh test.sh #在子進程中執行
- sh -x test.sh #會在終端打印執行到命令,適合調試
- source test.sh #test.sh在父進程中執行
- . test.sh #不需要賦予執行權限,臨時執行
腳本退出碼
很多時候我們需要獲取腳本的執行結果,即退出狀態,通常0表示執行成功,而非0表示失敗。為了獲得退出碼,我們需要使用exit。例如:
- #!/bin/bash
- function myfun()
- {
- if [ $# -lt 2 ]
- then
- echo "para num error"
- exit 1
- fi
- echo "ok"
- exit 2
- }
- if [ $# -lt 1 ]
- then
- echo "para num error"
- exit 1
- fi
- returnVal=`myfun aa`
- echo "end shell"
- exit 0
這里需要特別注意的一點是,使用
- returnVal=`myfun aa`
這樣的句子執行函數,即便函數里面有exit,它也不會退出腳本執行,而只是會退出該函數,這是因為exit是退出當前進程,而這種方式執行函數,相當于fork了一個子進程,因此不會退出當前腳本。最終結果就會看到,無論你的函數參數是什么***end shell都會打印。
- ./test.sh;echo $?
- 0
總結
以上就是shell編程最基本也是最關鍵的內容。當然這并非全部,例如數組,字典,參數處理等都沒有詳細介紹,由于篇幅有限,將會在后面的文章中進行詳細介紹。學好shell,解放你的雙手。