shell腳本教程
1 什么是shell腳本
Shell 是一個(gè)用 C 語言編寫的程序,它是用戶使用 Linux 的橋梁。Shell 既是一種命令語言,又是一種程序設(shè)計(jì)語言。Shell 腳本(shell script),是一種為 shell 編寫的腳本程序。
1.1 開發(fā)環(huán)境
Shell 編程跟 JavaScript、php 編程一樣,只要有一個(gè)能編寫代碼的文本編輯器和一個(gè)能解釋執(zhí)行的腳本解釋器就可以了。
Linux 的 Shell 種類眾多,常見的有:
- Bourne Shell(/usr/bin/sh或/bin/sh)
- Bourne Again Shell(/bin/bash)
- C Shell(/usr/bin/csh)
- K Shell(/usr/bin/ksh)
- Shell for Root(/sbin/sh)
- ……
1.2 初步體驗(yàn)
程序開發(fā)一般都是以一個(gè)hello world 開始,這里我們也不免俗,新建一個(gè)test.sh的文件,寫入內(nèi)容如下:
#!/bin/bash
echo "Hello World !"
#! 是一個(gè)約定的標(biāo)記,它告訴系統(tǒng)這個(gè)腳本需要什么解釋器來執(zhí)行,即使用哪一種 Shell。echo 命令用于向窗口輸出文本。
在linux上運(yùn)行shell腳本,需要先將腳本文件更改為可執(zhí)行。然后執(zhí)行。
chmod +x ./test.sh #使腳本具有執(zhí)行權(quán)限
./test.sh #執(zhí)行腳本
1.3 語言學(xué)習(xí)的流程
語言學(xué)習(xí)的流程我這邊總結(jié)了比較通用的步驟,這里一定存在一定的狹隘的看法,僅供參考。步驟如下:
1,變量的定義、語法、使用
2,運(yùn)算符
3,流程控制(條件語句、循環(huán)語句)
4,函數(shù)的定義和使用
5,...
2 shell腳本基礎(chǔ)語法
2.1 變量
# 什么是變量?
變量的概念基本上和初中代數(shù)的方程變量是一致的,只是在計(jì)算機(jī)程序中,變量不僅可以是數(shù)字,還可以是任意數(shù)據(jù)類型.
shell腳本中的變量一般只有兩種:數(shù)字和字符串。
# 變量的定義
變量的定義有兩種方式,直接賦值或者語句賦值。
a,直接賦值
my_name="zhangsan" # 定義了一個(gè)值為zcw的變量,變量的名為my_name
my_age=30 # 定義了值為30的變量,變量名為my_age
需要注意:
1、命名只能使用英文字母,數(shù)字和下劃線,首個(gè)字符不能以數(shù)字開頭
2、中間不能有空格,可以使用下劃線(_)
3、不能使用bash里的關(guān)鍵字
4、變量賦值語句等號(hào)兩側(cè)不能有空格,這點(diǎn)和其他開發(fā)語言不一樣
b,語句賦值
dir_list=`ls` # dir_list的值即為當(dāng)前文件下全部文件和文件夾名稱
需要注意:
1、ls為linux命令列出當(dāng)前文件下全部文件和文件夾
2、這種linux命令需要使用(`)包括
# 變量的使用
shell腳本變量的使用和其他語言不同,如java、php、python、c、c++等都是直接引用變量名即可,shell腳本中是需要在變量名前加上($)符號(hào)的。
my_name="zhangsan"
echo $my_name
echo ${my_name}
推薦使用第二種方式,加花括號(hào)是為了幫助解釋器識(shí)別變量的邊界,比如下面這種情況
echo "my name is $my_namei am ok!"
# 字符串
字符串的可以用單引號(hào),也可以用雙引號(hào),也可以不用引號(hào)。一般不推薦不用引號(hào)。
這里主要說下單引號(hào)和雙引號(hào)的區(qū)別。
a,單引號(hào)
1、單引號(hào)里的任何字符都會(huì)原樣輸出,單引號(hào)字符串中的變量是無效的
2、單引號(hào)必須成對出現(xiàn)
b,雙引號(hào)
1、雙引號(hào)可用有變量
2、雙引號(hào)可用出現(xiàn)轉(zhuǎn)義字符
示例
your_name="runoob"
# 使用雙引號(hào)拼接
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting $greeting_1
# 使用單引號(hào)拼接
greeting_2='hello, '$your_name' !'
greeting_3='hello, ${your_name} !'
echo $greeting_2 $greeting_3
hello, runoob ! hello, runoob !
hello, runoob ! hello, ${your_name} !
字符串兩個(gè)方法:
1、獲取字符串長度
string="abcd"
echo ${#string} #輸出 4
2、提取字符串
string="runoob is a great site"
echo ${string:1:4} # 輸出 unoo
# 數(shù)組
bash支持一維數(shù)組、類似于 C 語言,數(shù)組元素的下標(biāo)由 0 開始編號(hào)。
array_name=(value0 value1 value2 value3) #這是一個(gè)定義的數(shù)組
讀取數(shù)組
${array_name[n]} # n這里為實(shí)際的數(shù)字,范圍為0——數(shù)組長度-1
2.2 運(yùn)算符
shell運(yùn)算符主要包括:
- 算數(shù)運(yùn)算符
- 關(guān)系運(yùn)算符
- 布爾運(yùn)算符
- 字符串運(yùn)算符
- 文件測試運(yùn)算符
這里我簡單講解下算數(shù)運(yùn)算、關(guān)系運(yùn)算和邏輯運(yùn)算。
據(jù)名知意,算數(shù)就是計(jì)算,關(guān)系是進(jìn)行比較的,邏輯就是與或非。
# 算數(shù)運(yùn)算
原生bash不支持簡單的數(shù)學(xué)運(yùn)算,但是可以通過其他命令來實(shí)現(xiàn),例如 awk 和 expr,expr 最常用。如:
val=`expr 2 + 2` # 前面講過(`)是執(zhí)行的linux命令
echo "兩數(shù)之和為 : $val"
# 關(guān)系運(yùn)算
關(guān)系運(yùn)算符只支持?jǐn)?shù)字,不支持字符串,除非字符串的值是數(shù)字。
注:
1、需要使用[]包括
2、也可使用test 替換掉[]
2.3 流程控制
主要是控制程序的執(zhí)行,程序運(yùn)行一般都是按照順序執(zhí)行的,不過也有特殊的,如其他語言中的異步、回調(diào)等,不過在shell中一般只考慮順序執(zhí)行即可。順序執(zhí)行時(shí)我們可用通過條件語句來控制程序等運(yùn)行。
條件語句這里主要介紹下三種常見的:if語句、for循環(huán)、case...esac
# if語句
a=10
b=20
if [ $a == $b ]
then
echo "a 等于 b"
elif [ $a -gt $b ]
then
echo "a 大于 b"
elif [ $a -lt $b ]
then
echo "a 小于 b"
else
echo "沒有符合的條件"
fi
# for語句
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done
for file in `ls`
do
echo file
done
# case...esac語句
echo '輸入 1 到 4 之間的數(shù)字:'
echo '你輸入的數(shù)字為:'
read aNum
case $aNum in
1) echo '你選擇了 1'
;;
2) echo '你選擇了 2'
;;
3) echo '你選擇了 3'
;;
4) echo '你選擇了 4'
;;
*) echo '你沒有輸入 1 到 4 之間的數(shù)字'
;;
esac
2.4 函數(shù)
一次定義多處使用。
funWithReturn(){
echo "這個(gè)函數(shù)會(huì)對輸入的兩個(gè)數(shù)字進(jìn)行相加運(yùn)算..."
echo "輸入第一個(gè)數(shù)字: "
read aNum
echo "輸入第二個(gè)數(shù)字: "
read anotherNum
echo "兩個(gè)數(shù)字分別為 $aNum 和 $anotherNum !"
return $(($aNum+$anotherNum))
}
funWithReturn
echo "輸入的兩個(gè)數(shù)字之和為 $? !"
3 ()、(())、[]、[[]]、{}的作用和區(qū)別
$()和 ` `
在 bash shell 中,$( ) 與` ` (反引號(hào)) 都可用做命令替換用。
例如
version=$(uname -r)和version=`uname -r`都可以是version得到內(nèi)核的版本號(hào)
各自的優(yōu)缺點(diǎn):
1、` ` 基本上可用在全部的 unix shell 中使用,若寫成 shell script ,其移植性比較高,但反單引號(hào)容易打錯(cuò)或看錯(cuò)。
2、$()并不是所有shell都支持。
${ }
${ }用于變量替換。一般情況下,$var 與${var} 并沒有什么不一樣,但是用 ${ } 會(huì)比較精確的界定變量名稱的范圍。
$[] $(())
$[]和$(())是一樣的,都是進(jìn)行數(shù)學(xué)運(yùn)算的。支持+ - * / %(“加、減、乘、除、取?!保5亲⒁?,bash只能作整數(shù)運(yùn)算,對于浮點(diǎn)數(shù)是當(dāng)作字符串處理的。
[ ]
為test命令的另一種形式,但要注意:
1.必須在左括號(hào)的右側(cè)和右括號(hào)的左側(cè)各加一個(gè)空格,否則會(huì)報(bào)錯(cuò)。
2.test命令使用標(biāo)準(zhǔn)的數(shù)學(xué)比較符號(hào)來表示字符串的比較,而用文本符號(hào)來表示數(shù)值的比較。
3.大于符號(hào)或小于符號(hào)必須要轉(zhuǎn)義,否則會(huì)被理解成重定向。
(( ))及[[ ]]
分別是[ ]的針對數(shù)學(xué)比較表達(dá)式和字符串表達(dá)式的加強(qiáng)版。
[[ ]]中增加模式匹配特效。
(( ))不需要再將表達(dá)式里面的大小于符號(hào)轉(zhuǎn)義。
4 實(shí)際案例
# 案例1,關(guān)閉javaweb程序
#!/bin/bash
name=$(lsof -i:80|tail -1|awk '"$1"!=""{print $2}')
if [ -z $name ]
then
echo "No process can be used to killed!"
exit 0
fi
id=$(lsof -i:8080|tail -1|awk '"$1"!=""{print $2}')
kill -9 $id
echo "Process name=$name($id) kill!"
exit 0
# 案例2,云平臺(tái)一鍵配置
#!/bin/bash
# 此腳本用于一鍵web環(huán)境及項(xiàng)目配置
# ver1.0
www="/home/wwwroot/default"
commands=(all ip lnmp web)
lnmpSetFun(){
echo "修改lnmp配置信息"
# php修改
sed -i 's|proc_open,||' /usr/local/php/etc/php.ini && is_php=1 || is_php=0
if test $is_php -eq 0
then
echo "lnmp尚未安裝,lnmp配置失??!"
exit
fi
sed -i 's|proc_get_status,||' /usr/local/php/etc/php.ini
sed -i '/PHP_ADMIN_VALUE/d' /usr/local/nginx/conf/fastcgi.conf
service php-fpm restart
# nginx修改
sed -i '/$query_string/d' /usr/local/nginx/conf/nginx.conf
sed -i '/include enable/a\ location / {try_files $uri $uri/ /index.php?$query_string;}' /usr/local/nginx/conf/nginx.conf
sed -i '/root/d' /usr/local/nginx/conf/nginx.conf
sed -i '/index index/a\ root '"$www"'/public;' /usr/local/nginx/conf/nginx.conf
service nginx restart
echo "lnmp配置完成!"
}
webSetFun(){
chmod -R 777 $www/storage && is_web=1 || is_web=0
if test $is_web -eq 0
then
echo "注意!網(wǎng)站未放入或網(wǎng)站路徑!網(wǎng)站配置失??!"
exit
fi
chmod -R 777 $www/public
cp /home/wwwroot/default/back.php $www/.env
echo "網(wǎng)站配置完成!"
}
webIpFun(){
read -p "請輸入本機(jī)IP: " ip
api_ip="http://${ip}"
if [ -z $ip ]
then
echo "尚未輸入IP,IP配置失?。?
exit
else
sed -i '/baseUrl/d' $www/public/js/config.js
sed -i '/commandUrl/d' $www/public/js/config.js
sed -i '/^PLATFROM_CONFIG.title/i\PLATFROM_CONFIG.baseUrl = \"'"$api_ip"'\"' $www/public/js/config.js
sed -i '/^PLATFROM_CONFIG.title/i\PLATFROM_CONFIG.commandUrl = \"'"$ip"'\"' $www/public/js/config.js
sed -i '/APP_URL/d' $www/.env
sed -i '/SERVER_URL/d' $www/.env
sed -i '/^ADMIN_HTTPS/i\APP_URL='"$api_ip"'' $www/.env
sed -i '/^ADMIN_HTTPS/i\SERVER_URL='"$api_ip"':8080/energy_command/' $www/.env
echo "IP配置完成!"
fi
}
case $1 in
${commands[0]})
lnmpSetFun
webSetFun
webIpFun
;;
${commands[1]})
webIpFun
;;
${commands[2]})
lnmpSetFun
;;
${commands[3]})
webSetFun
;;
*)
echo "輸入指令不正確!"
echo "正確格式為 \"./webset.sh cmd\""
echo "其中cmd包含有all、ip、lnmp、web"
echo "all為一鍵配置全部,按照說明書正常步驟執(zhí)行完即可操作"
echo "ip單配置后臺(tái)及前臺(tái)ip地址"
echo "lnmp單配置lnmp服務(wù)"
echo "web單配置web服務(wù)"
;;
esac
echo "配置完成,瀏覽器輸入\"http://本機(jī)ip\"訪問項(xiàng)目"
# 案例3,云平臺(tái)項(xiàng)目部署
#!/bin/bash
# 此腳本用于一鍵部署web項(xiàng)目
# ver1.0
wwwPlat="/home/wwwroot/default"
wwwServer="/home/wwwroot/server"
platMoveFun(){
if [ -e $wwwPlat ]
then
echo "~~~~"
else
`mkdir -p ${wwwPlat}`
fi
`tar -xzvf ./energy_cloud_platform.tar.gz -C ${wwwPlat}`
}
serverMoveFun(){
if [ -e $wwwServer ]
then
`rm -rf ${wwwServer}/*`
else
`mkdir -p ${wwwServer}`
fi
`\cp ./energy_cloud/* ${wwwServer}`
}
echo "###一鍵部署web文件###"
serverMoveFun
platMoveFun
echo "部署完成!"
5 結(jié)語
我這里只是帶著簡單過了下shell腳本的一些常用語法,實(shí)際學(xué)習(xí)還需要進(jìn)一步去看文檔。
shell語言其實(shí)只是簡單的基本操作語言,要讓其發(fā)揮作用還需要深入學(xué)習(xí)下linux命令,課程中大家應(yīng)該也看到了,其實(shí)很多地方都需要用到linux的命令獲取到數(shù)據(jù)給我們的變量中讓我們在進(jìn)一步處理。
我對于shell的理解是,其實(shí)它就是對linux命令提供了更方便的操作和處理方式。
這里我在列下自己目前常用的linux命令。http://m.itdecent.cn/p/7f68c0945f2f