Bash Shell 腳本編寫入門
這是關於編寫Bash Shell腳本的詳細概述。
腳本編寫是一種自動化在計算機上定期執行的任務的強大方式。
在本教程中,將詳細介紹腳本編寫,並將成為進一步深入和高級教程創建實際腳本的基本參考。
查看我的Bash介紹文章。
Bash提供了一組命令,這些命令組合在一起可以用來創建小程序,按照慣例我們稱之為腳本。
請注意區別。我們不說Bash編程,而說Bash腳本,我們也不稱Bash腳本為”Bash程序”。這是因為在您的腳本變得失控之前,通常可以達到一定的複雜性。
但是Bash腳本非常棒,因為您執行它們時不需要任何其他東西,只需要Bash本身。沒有編譯器,沒有解釋器,只需要您的shell。
與Perl、JavaScript或Python等編程語言相比,您會錯過很多東西。
變量沒有作用域,它們全部是全局的,沒有標准庫,也沒有模塊系統,例如。但優點也非常大:您可以非常輕鬆地像在shell中那樣調用任何CLI工具,且Unix的許多小型實用程序命令的方法確實使腳本編寫能力出眾。使用wget
執行網絡請求,使用awk
處理文本等等。
Shell腳本是您最好了解的工具之一,至少知道如何在看到它時讀取程序以及它能為您的日常工作帶來的好處。
本教程將指導您了解Bash腳本的理論和概念。將來我將發布更詳細的教程,介紹特定技術或如何解決特定問題。
基礎知識
腳本存儲在文件中。您可以給shell腳本任何名稱和擴展名,這無關緊要。重要的是它必須在第一行上以”shebang”開始:
1 | #!/bin/bash |
並且它必須是一個可執行文件。
使用chmod
這個命令使文件變為可執行:
1 | chmod u+x myscript |
將myscript
文件設置為您的用戶可執行(我將不會深入探討權限問題,但我將很快介紹它們)。
現在,如果您在同一文件夾中,可以通過調用./myscript
或使用其完整路徑來執行腳本。
在學習時,我建議您,如果可能的話,使用在線環境進行測試,像這樣的https://rextester.com/l/bash_online_compiler。
註釋
註釋是編寫程序時最重要的事情之一。以“#”符號開頭的行是註釋(除了上面這裡看到的shebang行)。
例如:
1 | #!/bin/bash |
註釋也可以在行末開始:
1 | #!/bin/bash |
變量
您可以使用“=”運算符設置變量:
1 | name=value |
示例:
1 | ROOM_NUMBER=237 |
您可以使用 echo
內建命令打印變量並在變量名前加上 $
:
1 | echo $ROOM_NUMBER |
運算符
Bash實現了一些在編程語言中常用的算術運算符:
+
加-
減*
乘/
除%
取餘數**
指數
您可以使用以下方式進行比較:
<
小於<=
小於等於==
等於>=
大於等於>
大於
您還可以使用這些比較運算符:
-lt
小於-gt
大於-le
小於等於-ge
大於等於-eq
等於-ne
不等於
例如:
1 | #!/bin/bash |
邏輯運算符:
&&
邏輯“且”||
邏輯“或”
這些快捷方式允許執行算術操作,然後進行分配:
+=
-=
*=
/=
%=
還有一些其他運算符,但這些是最常見的。
輸出到屏幕
您可以使用 echo
命令將任何內容輸出到屏幕:
1 | #!/bin/bash |
邏輯條件
AND:如果command
和anothercommand
都執行並返回0,則求值為0(零)。在shell命令中,返回零表示命令成功執行。非零返回值表示錯誤消息。
1 | command && anothercommand |
OR:如果command
和anothercommand
中至少有一個執行並返回0,則求值為0(零)。
1 | command || anothercommand |
NOT:反轉command
邏輯返回值:
1 | ! command |
控制結構
您可以使用幾個您可能熟悉的控制結構:
if/else語句
簡單if
:
1 | if condition |
if
…else
:
1 | if condition |
嵌套的if
- else
:
1 | if condition |
使用分號將else
放在同一行上可以達到與上面示例相同的效果:
1 | if condition ; then |
示例:
1 | #!/bin/bash |
請注意括號?在進行任何類型的布爾表達式評估時,我們必須添加括號。
循環
while循環
當condition
成立時,運行command
1 | while condition |
until
直到condition
成立時,運行command
1 | until condition |
for循環
遍歷列表,對每個項目運行一個命令
1 | for item in list |
跳出和繼續
在循環內部,您可以使用break
和continue
語句完全退出循環,或者只是跳過當前迭代。
Case
case
控制結構根據值選擇不同的路徑。
1 | case value in |
與fi
一樣,esac
結束case
結構,注意它的拼寫是反過來的。
我們在每個case
後面添加雙分號。
*)
用於處理未明確表示的所有情況。
使用|
符號可以表示同一個case
的多個選項。
示例:
1 | #!/bin/bash |
Select
select
控制結構向用戶顯示可選菜單:
1 | select item in list |
示例:
1 | #!/bin/bash |
條件測試
在上面的控制結構中,我使用condition
這個詞。
您可以使用test
Bash內建命令檢查條件並返回true(0
)或false(非0
)的值。
下面是一個示例:
1 | #!/bin/bash |
從命令行讀取輸入
您可以使用read
內建命令使腳本變得互動。該命令從標準輸入讀取一行,並且可以以非常靈活的方式格式化輸入。
最簡單的用法是:
1 | echo "Age:" |
這會打印“Age:”,然後您可以輸入一個數字,按Enter鍵,該數字將被賦值給age
變量。
read
的-p
選項提供了內建的提示符,並將輸入放入age
變量中:
1 | read -p "Age: " age |
read
命令還有更多選項,可以通過在Bash中輸入help read
來檢查。
添加選項
選項使用連字符和字母指定,例如:
1 | ls -a |
在代碼中,您使用內建命令getopts
來解析選項並獲取值。
如果我們接受選項a
和b
,我們將getopts ab
提供給while循環。
如果選項b
接受值,則在之後添加冒號:
,所以我們的getopts
調用的格式是這樣的:getopts ab: arg
以下是代碼片段:
1 | while getopts xy: arg |
在此腳本中,$OPTARG
自動分配為選項字母。我們告訴getopts
我們接受哪些選項,並分別處理每種情況。
getopts
會自動處理錯誤,我們可以選擇自己處理錯誤消息,只需在參數定義之前加冒號:xy:
:getopts :xy: arg
。
然後,我們還需要處理\?
和:
情況。當我們傳入無效選項時,將調用第一個,而當我們錯過選項時,將調用第二個:
1 | while getopts :xy: arg |
現在,如果您忘記添加參數,錯誤消息將不同。
處理參數
在腳本內,您可以訪問在調用時傳遞的任何參數。您使用$0
,$1
,$2
等來訪問它們,具體取決於位置,其中$0
是命令的名稱,並且增加數字則是參數位置的增加。在位置9之後,您需要使用大括號:${10}
,${11}
……
例如,運行此startCar
腳本:
1 | #!/bin/bash |
作為./startCar fiesta
運行將打印:
1 | ./startCar |
特殊的$*
語法打印所有參數,$#
是傳遞的參數數量:
1 | #!/bin/bash |
1 | ./test.sh Milan Florence Rome |
分離選項和參數
如果您既有選項又有參數,您需要將它們分開。您可以使用連字符:
1 | driveCar -m "Ford Fiesta" - Milan Florence Rome |
使用“getopts”內置命令解析選項並獲取值。
功能
就像在JavaScript或其他任何編程語言中一樣,您可以創建可重複使用的小代碼塊,給它們命名,在需要時調用它們。
Bash稱之為函數。
您使用以下方式定義一個函數:
1 | function name { |
示例:
1 | function cleanFolder { |
並且您可以像這樣調用它:
1 | cleanFolder |
您可以將參數傳遞給文件夾,而不需要聲明它們 - 只需像腳本參數一樣引用它們:$1
,$2
等。例如:
1 | function cleanFolder { |