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