做 Java 的肯定都接觸過 Linux 系統(tǒng),那么很多時候我們在開發(fā)的過程中都是把我們項目打成一個jar包,或者是war包的形式,然后通過 XFTP 上傳到我們服務器的指定目錄,然后運行一端啟動腳本,讓我們的項目變得可以訪問 就像???./sh service.sh start?
??然后啟動我們寫好的???sh?
??的shell腳本。接下來我們就來學習一下關于 Shell 腳本是如何寫出來的。
Shell 腳本
Shell 腳本是什么?Shell是一個命令解釋器,它的作用是解釋執(zhí)行用戶輸入的命令及程序等,也就是說,我們用戶每輸入一條命令,Shell 就會相對應的執(zhí)行一條命令。當命令或程序語句不在命令行下執(zhí)行,而是通過一個程序文件來執(zhí)行時,該程序文件就被稱為Shell腳本。
在我們的 Shell 腳本中,會有各種各樣的內容,賦值,計算,循環(huán)等一系列的操作,接下來我們就來看看這個 Shell 腳本怎么寫吧
1.查看自己當前系統(tǒng)默認的 Shell
??echo $SHELL?
?
輸出:/bin/bash
2.查看系統(tǒng)支持的Shell
??cat /etc/shells?
?
輸出:
/bin/sh /bin/bash /usr/bin/sh /usr/bin/bash
也就是說,我們的云服務器是支持我們在這里給他安排 Shell 腳本的
Shell 腳本怎么寫出來的
我們這時候先來安排一下???sh?
???的文件,創(chuàng)建一個文件夾,然后在其中創(chuàng)建一個???sh?
??的文件。
??mkdir /usr/local/shelltest?
?
??touch test.sh?
?
創(chuàng)建完成我們編輯一下內容
??vim test.sh?
?
#!/bin/bash
echo "Hello World Shell"
然后我們出來運行一下我們的 Shell 的第一個腳本
??bash test.sh?
?
出來的結果是???Hello World Shell?
?
一個及其簡單的腳本出現(xiàn)了,接下我們就分析一波我們寫了點啥?
??#!/bin/bash?
?
#! 是一個約定的標記,它告訴系統(tǒng)這個腳本需要什么解釋器來執(zhí)行,即使用哪一種 Shell
我們在之前也使用了???echo $SHELL?
???來查看了自己系統(tǒng)默認的是哪一種???sh?
??解析器,之前看到的是/bin/bash,所以我們在寫 Shell 腳本的時候,我們在開頭默認的約定中,我們寫了這個是用 /bin/bash 來進行解釋的,
那么我們如何像之前調用我們的當前目錄中的 Shell 腳本一樣去調用他呢?就像這個樣子的???./sh service.sh start?
?
1.授權,
我們先不授權試一下看看能通過 ./test.sh 進行調用么
bash: ./test.sh: Permission denied 會提示這個,也就是沒有授權定義,
授權命令:chmod +x test.sh
2.執(zhí)行 ./test.sh
然后調用就能正常輸出了,就是說,在當前的目錄下執(zhí)行這個腳本命令。
Shell 腳本的變量
- 定義變量和使用
變量命名實際上很簡單,我們先來試一下
??name=zhiyikeji?
?
這時候我們怎么使用變量呢?實際上只要在前面加上一個符號就可以 $
??echo $name?
?
[root@iZbp10j01t7sgfqekyefpoZ ~]# echo $name
zhiyikeji
[root@iZbp10j01t7sgfqekyefpoZ ~]# echo ${name}
zhiyikeji
上面的兩種寫法都是可以的,外面的大括號加和不加區(qū)別不大,可以省略,直接就??$name?
??就可以使用你定義的變量
使用括號的意義一般在于區(qū)別某些變量,比如你寫了一串的內容,可能寫的是???echo $nameismyfriend?
??,如果連在一起,是不是有點尷尬,這時候就可以使用括號區(qū)別一下,??echo ${name}ismyfriend?
??不使用括號的時候,他就去找nameismyfriend這個變量了,就無法出來我們要的效果。
- 刪除自己定義的變量
??unset name?
?
這時候我們就把我們剛才定義的???name=zhiyikeji?
??這個變量給去掉了,我們可以調用一下我們的變量看是什么?
??echo $name?
?
[root@iZbp10j01t7sgfqekyefpoZ ~]# unset name
[root@iZbp10j01t7sgfqekyefpoZ ~]# echo $name
這是不是就證明我們自己定義的變量已經刪除了
- 只讀變量
那么我們需要一個關鍵字,大家肯定能想到是什么關鍵字???readonly?
?
我們先給name賦值,然后使用 readonly 設置只讀,然后再改變一下試試,
[root@iZbp10j01t7sgfqekyefpoZ ~]# name=zhiyikeji
[root@iZbp10j01t7sgfqekyefpoZ ~]# echo $name
zhiyikeji
[root@iZbp10j01t7sgfqekyefpoZ ~]# readonly name
[root@iZbp10j01t7sgfqekyefpoZ ~]# echo $name
zhiyikeji
[root@iZbp10j01t7sgfqekyefpoZ ~]# name=ceshi
-bash: name: readonly variable
[root@iZbp10j01t7sgfqekyefpoZ ~]#
竟然是真的,如果不設置只讀,是不是會重新可以進行賦值,我們測試個年齡,
[root@iZbp10j01t7sgfqekyefpoZ ~]# age=10
[root@iZbp10j01t7sgfqekyefpoZ ~]# echo $age
10
[root@iZbp10j01t7sgfqekyefpoZ ~]# age=20
[root@iZbp10j01t7sgfqekyefpoZ ~]# echo $age
20
所以我們就可以肯定,readonly就是設置只讀的關鍵詞,記住了么?
那么設置只讀的變量可以刪除么?畢竟總有杠精的面試官會提問這個棘手的問題,但是,阿粉試過的所有方式好像都是不行的,阿粉就直接重啟了自己的服務器,這樣臨時的變量就不存在了!
Shell 腳本的流程控制
說真的,Shell腳本的流程控制數(shù)一般才是yyds,為什么這么說,因為你在寫大部分的腳本的時候,流程控制的地方永遠是最多的,判斷,選擇,等等一系列的函數(shù),當時熟練使用的時候,就發(fā)現(xiàn)這東西確實很有意思。
IF
我們先說最簡單的???if else?
???這也是我們最經常使用的判斷,在寫???Shell?
??腳本的時候,就不像我們的 Java 中直接寫
if(...){
}else{
....
}
??Xshell?
???中的語法就不是這個樣子的,??Xshell?
?語法:
if ...
then
...
else
...
fi
末尾的 fi 就是 if 倒過來拼寫,我們可以寫一個???if?
??的腳本試一下這個流程能否理解。
#! /bin/bash
if [ $1 -gt 2 ];
then
echo "值大于2"
else
echo "值小于2"
exit
fi
這里申明一下,
- ?
?-ge?
?標識的是大于等于符號; - ?
?-le?
?表示的是小于等于符號; - ?
?-gt?
??表示大于符號; - ?
?-lt?
??表示小于符號; - ?
?-eq?
??表示等于符號; - ?
?-ne?
??表示不等于符號;
我們在上面這段腳本中寫就是內容就是,我們給腳本傳入一個值,然后比對這個值和2的大小關系,然后輸出我們指定的內容。
運行后就能看到
[root@iZbp10j01t7sgfqekyefpoZ shelltest]# sh test2.sh 1
值小于2
[root@iZbp10j01t7sgfqekyefpoZ shelltest]# sh test2.sh 3
值大于2
??$1?
???表示我們給 Shell 腳本輸入的第一個參數(shù),???$0?
?就是你寫的shell腳本本身的名字,$2 是我們給 Shell 腳本傳的第二個參數(shù)
大家在部署某些項目的時候,是不是啟動命令就很簡潔,就是???sh service.sh start?
???類似這種的,那我們來看看一般這種是怎么寫的,這就用到了另外一塊的內容,和???if?
???類似,在 Java 中也有,那就是???Case?
?.
Case
我們先來看看???Case?
??的語法,
??case ... esac?
???實際上就和 Java 中的 Case 是非常相似的,case 語句匹配一個值與一個模式,如果匹配成功,執(zhí)行相匹配的命令.??esac?
?是一個結束的標志。
case 值 in
匹配值1)
command1
command2
;;
匹配值2)
command1
command2
;;
esac
光說不練,假把式,我們來搞一下試試寫一個腳本來搞一下。就用我們剛才說的???sh servic.sh start?
??來進行測試。
case $1 in
start)
#輸出啟動命令
echo "start已經開始"
;;
stop)
#輸出停止命令
echo "stop命令執(zhí)行"
;;
esac
exit
我們來看看運行結果
[root@iZbp10j01t7sgfqekyefpoZ shelltest]# sh service.sh start
start已經開始
[root@iZbp10j01t7sgfqekyefpoZ shelltest]# sh service.sh stop
stop命令執(zhí)行
那么這段 Shell 腳本是什么意思呢?其實很簡單,匹配我們傳入的第一個字符,和???start?
???還有???stop?
??進行比較,如果匹配上之后,輸出命令,最后退出即可。
是不是感覺沒有那么復雜了呢?
For
說到流程控制,那么肯定不能不說 for , 畢竟 for 循環(huán)在 Java 中那可是重頭戲。
我們先看他的格式
for i in item1 item2 ... itemN
do
command1
command2
...
commandN
done
那么我們有沒有說像是 Java 中那種 for 循環(huán)一樣的方式呢?比如說這個??for ((i=1; i<=j; i++))?
?
實際上也是支持這種的,我們來寫一個試試。
j=$1
for ((i=1;i<=j;i++))
do
echo $i
done
執(zhí)行一下看看
[root@iZbp10j01t7sgfqekyefpoZ shelltest]# sh fortest.sh 6
1
2
3
4
5
6
既然有 for 那是不是就有 while 呢?是的,沒錯,確實是有 while ,也是循環(huán)的意思,但是寫法有略微不一樣的地方
While
while condition
do
command
done
我們來舉個嘗試打印九九乘法表來看一下
a=1
b=1
while ((a <=9))
do
while ((b<=a))
do
let "c=a*b" #聲明變量c
echo -n "$a*$b=$c "
let b++
done
let a++
let b=1 #因為每個乘法表都是1開始乘,所以b要重置
echo "" #顯示到屏幕換行
done
[root@iZbp10j01t7sgfqekyefpoZ shelltest]# sh whileTest.sh
1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8 4*3=12 4*4=16
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
是不是也挺簡單的?
其實 Shell 腳本的編寫一般都是在實際應用中提升,單純的寫測試腳本,也是可以讓自己對知識的掌握比較充分,而我們一般都是寫一些比較簡單的腳本,復雜的不是還有運維么?
< END >
告訴大家一個好消息,Java極客技術讀者交流群(摸魚為主),時隔 2 年后再次開放了,感興趣的朋友,可以在公號回復:999
本文摘自 :https://blog.51cto.com/u