Shell是一種編程語言, 它像其它編程語言如: C, Java, Python等一樣也有變量/函數(shù)/運算符/if語句/循環(huán)控制/… 但在開始之前, 我想先理清Shell語言與Shell之間的關(guān)系.
Shell與Shell語言
上面說了Shell是一種編程語言但你可能也聽說過: sh/bash/csh/zsh/…它們也叫Shell, 實際上這里所說的Shell是一種應(yīng)用程序, 它負責(zé)解釋執(zhí)行你編寫的Shell腳本, Mac默認就自帶了sh/bash/csh/zsh/tcsh/ksh, 你可以這樣查看cat /etc/shells
不同的shell的用法基本相同, 但有些shell提供了一些新特性, 比如我現(xiàn)在在用的就是zsh, 更多zsh的內(nèi)容可以去看這篇文章
第一個Shell腳本
#! /bin/sh
echo "hello shell!"
依國際慣例這里以在終端里打印一句hello shell!開始, 第一行的#!是一個約定標記, 它告訴腳本這段腳本需要什么解釋器來執(zhí)行. 第二行的echo命令則負責(zé)向屏幕上輸出一句話.
如何運行
運行shell程序有3種方法:
chmod +x使文件具有可執(zhí)行權(quán)限, 直接運行
直接調(diào)用解釋器, 將腳本文件作為參數(shù)傳入 (比如bash hi.sh)
使用source(也可用 . 代替)執(zhí)行文件
通常情況下, 最方便的方式就是方式1, 通過方式1執(zhí)行你需要在腳本第一行寫好這段腳本由哪個解釋器來解釋, 而通過方式2來執(zhí)行則沒有這個限制, 寫了也沒用.
除此之外方式1與方式2執(zhí)行命令就沒有區(qū)別了, 但方式3執(zhí)行的方式與前兩種都不同:
使用source執(zhí)行shell腳本時, 不會創(chuàng)建子進程, 而是在父進程中直接執(zhí)行!
這里不作更多解釋, 感興趣的同學(xué)可以去參考Linux Shell編程從入門到精通這本書的第一章的相關(guān)部分.
變量
和其它語言一樣Shell中也有變量, 而且更簡單, 但有一些比較特殊的地方.
Shell中的變量只有字符串這一種類型
Shell中變量名與變量值沒有長度限制
Shell的變量也允許比較操作和整數(shù)操作, 只要變量中的字符串為數(shù)字
定義變量
variable_name=ghui
需要注意: = 兩邊不能加空格, 當(dāng)賦值語句包含空格時請加引號(單引號/雙引號均可)比如:
variable_name="ghui's blog"
Shell中的變量可以分為兩種類型:
局部變量 (定義變量時在前面加local修飾符)
全局變量 (定義變量時不加任何修飾符)
與其它語言一樣局部變量的可見范圍是代碼塊或函數(shù)內(nèi), 全局變量在全局范圍內(nèi)可見.看個簡單的例子:
#! /bin/sh
num=111 #全局變量
func1()
{
?local num=222 #局部變量
?echo $num
}
echo "before---$num"
func1
echo "after---$num"
輸出:
before---111
222
after---111
使用變量
使用一個定義過的變量, 只要在變量名前面加$即可, 如:
name=ghui
echo $name
echo ${name} #{} 為了幫助解釋器識別變量邊界, 非必須
在使用變量時還有一個地方需要注意, 請看下面的例子:
#! /bin/sh
str='abc'
echo "1 print $str"
echo '2 print $str'
輸出:
1 print abc
2 print $str
即:
被雙引號括起來的變量會發(fā)生變量替換, 單引號不會
注釋
Shell中注釋使用#, 而且它不支持多行注釋.
常用的字符串操作
字符串拼接
name="shell"
sayHi="hello, "$name" !"
sayHi2="hello, ${name} !"
echo $sayHi $sayHi2
注意: 上面說的單雙引號引起的變量替換問題
獲得字符串長度
string="abcd"
echo ${#string} #輸出:4
截取字符串
str="hello shell"
echo ${str:2} ?#輸出: llo shell
echo ${string:1:3} #輸出:ell
更多關(guān)于字符串的操作可以看這個
if/else流程控制
基本語法結(jié)構(gòu):
if condition
then
do something
elif condition
then
do something
elif condition
then
do something
else
do something
fi
其中, elif語句和else語句非必須的.看個例子:
#! /bin/sh
a=1
if [ $1=$a ]
then
echo "you input 1"
elif [ $1=2 ]
then
echo "you input 2"
else
#do nothing
echo " you input $1"
fi
很簡單, 不過這里有兩個地方需要注意, 如果某個條件下的執(zhí)行體為空, 則你就不能寫這個條件 即下面這樣會報錯:
if condition
then
#do nothing
elif condition
then
# do nothing
#or
else
#do nothing
另外, [ ] 兩邊一定要加空格, 下面這樣都會報錯:
if [$a=$b]
#or
if [ $a=$b]
#or
if [$a=$b ]
只有這樣if [ $a=$b ]才是對的.
注意: 實際上這里的[]是test命令的一種形式, [是系統(tǒng)的一個內(nèi)置命令,存在路徑是/bin/[,它是調(diào)用test命令的標識, 右中括號是關(guān)閉條件判斷的標識, 因此下面的兩個測試語句是等效的:
if test "2>3"
then
...
fi
和
if [ "2>3" ]
then
…
fi
除[]之外, shell語言中還有幾種其它括號, 比如: 單小括號/雙小括號/雙中括號/… , 不同的括號有不同的用法, 更多關(guān)于shell中, 括號的用法可以看看這個
switch流程控制
當(dāng)條件較多時, 可以選擇使用switch語句, shell中的switch語句的寫法和其它語言還是有些不同的, 基本結(jié)構(gòu)如下:
case expression in
pattern1)
do something... ;;
pattern2)
do something... ;;
pattern2)
do something... ;;
...
esac
看個例子:
#! /bin/sh
input=$1
case $input in
? ? ? ?1 | 0)
? ? ? ?str="一or零";;
? ? ? ?2)
? ? ? ?str="二";;
? ? ? ?3)
? ? ? ?str="三";;
? ? ? ?*)
? ? ? ?str=$input;;
esac
echo "---$str"
這個例子會根據(jù)你執(zhí)行此腳本時傳入的參數(shù)不同在屏幕上輸出不同的值, 其中第一個case 1 | 0代表邏輯或.
NOTE:
;;相當(dāng)于其它語言中的break
每個pattern之后記得加)
最后記得加esac (即反的case)
for循環(huán)
基本結(jié)構(gòu):
for name [in list]
do
...
done
其中,[]括起來的 in list, 為可選部分, 如果省略in list則默認為in "$@", 即你執(zhí)行此命令時傳入的參數(shù)列表.
看個例子:
for file in *.txt
do
open $file
done
遍歷當(dāng)前目錄下的所有txt文件, 并依次打開.
while循環(huán)
基本結(jié)構(gòu):
while condition
do
do something...
done
看個例子:
#! /bin/sh
i=0
while ((i<5));
do
((i++))
echo "i=$i"
done
輸出:
i=1
i=2
i=3
i=4
i=5
NOTE: 你可能需要去了解一下(())的用法
until循環(huán)
基本結(jié)構(gòu)
until condition
do
do something...
done
看個例子:
#! /bin/sh
i=5
until ((i==0))
do
((i--))
echo "i=$i"
done
輸出:
i=4
i=3
i=2
i=1
i=0
跳出循環(huán)
shell中也支持break跳出循環(huán), continue跳出本次循環(huán).用法與C, Java中相同
函數(shù)
要定義一個函數(shù), 可以使用下面兩種形式:
function funcname()
{
do something
}
或者
funcname ()
{
do something
}
看個例子
#! /bin/sh
# ad.sh 計算sum
add()
{
let "sum=$1+$2"
return $sum
}
add $1 $2
echo "sum=$?"
輸入
ad 1 2
輸出
sum=3
其中, $?在shell中保存的是上一條命令的返回值
NOTE:
函數(shù)必須先定義后使用
如果在函數(shù)中使用exit會退出腳本, 如果想退回到原本函數(shù)調(diào)用的地方, 則可使用return
向腳本傳遞參數(shù)
先shell腳本傳遞參數(shù), 非常簡單, 只需要在你執(zhí)行命令的后面跟上即可, 看個例子:
#! /bin/sh
# test.sh
echo "$# parameters";
echo "$@";
echo "$0"
echo "$1"
輸入:
test.sh 11 22
輸出:
2 parameters
11 22
test.sh
11
后記
之所以要寫這篇博客, 有以下幾個原因:
想總結(jié)一下shell編程中的關(guān)鍵知識點, 方便日后查看.
想通過shell優(yōu)化一下我的hexo寫作及博客管理流程, 目前相關(guān)腳本已完成, 待我下一篇博客分享給大家, 如果你也是在用Hexo寫博客, 相信對你會很有用, 盡請期待! 已經(jīng)發(fā)布
可以看的出這里總結(jié)的都是最關(guān)鍵的知識點, 還有很多這里并沒有說. 是因為我覺得剛開始學(xué)習(xí)一個東西沒必要太計較一些細節(jié)/瑣碎的東西, 掌握好大致知識框架, 然后在大家編寫具體的腳本時, 遇到具體問題, 再去google尋找即可.