高級語言、腳本語言、解釋型語言:xxx.sh,一般基於 bash
課程內容#
第一個 Shell 腳本#
#!/bin/bash
#註解
echo "Hello"
- 第一行 #! 指定解釋器,只在第一行才有效
- 註解:"#"
變量#
a=123
a=hello
a=`pwd`
PATH=${PATH}:path # 變量後接字符串,可以直接拼接字符串
# 【注意】":a"有特殊含義,會指到當前路徑
特殊變量#
位置變量
結果:
-
$n:如果 n>9,需要用大括號括起來
-
$@ 和 $* 的區別在於:傳入參數分別被雙引號包圍、且 $ 變量也被雙引號包圍時,"$@" 會將所有的參數分開【一般情況】,而 "$*" 會將所有的參數作為一個整體
- 在用 for...in 時可以看出,詳見 Shell 特殊變量:Shell $0, $#, $*, $@, $?, $$ 和命令行參數——C 語言中文網
-
$#:不算 $0
狀態變量
- $?:【上一條】指令執行結果,0—— 成功,非 0—— 不成功
- 便於腳本自動判斷指令成功與否
- $$、$!:當前進程、最後運行的後台進程的 PID,一般用於自動化測試、多腳本交互場景
輸入輸出#
- 輸入:read
- -p:顯示友好提示,需在 bash 下使用
- -s:靜默模式
- -t:輸入等待時長,超時結束 (單位:s)
- 輸出:echo
- -e:開啟轉義
- 輸出:printf
- 和 C 語言的 printf 非常像!
- [PS] ! 和 \n 放一起有特殊含義,需要分開
- bash 下需要分開
- zsh 下可以分開,或用 \ 轉義
- 一般對於特殊符號—— 菜鳥教程,需要警覺!
函數#
-
沒有形參
-
定義:寫法很多,function、()、{} 組合搭配,第 3 種更類似 C 語言寫法
-
調用:函數名 參數...
- 加 function 方便閱讀
-
❗【注意】shell 中函數 return 的返回值有限制,範圍是 0-255,溢出會循環換算
流程控制#
do——done、if——then——fi、case——esac
【重點】TEST 表達式⭐#
- 可判斷類型:字符串、整型、文件
- ❗ 【注意】條件為真時,返回 0,否則返回非 0
- Linux 中命令的返回值也是如此,0 才代表成功
- [PS]
- STRING1 = STRING2 也可以用 == 【推薦後者,兩個中括號 [[]] 支持】
- -G FILE:文件存在並且被有效組 ID 擁有
- 如果組被解散了,則組控制的文件的組 ID 就是無效的
- 具體可查閱 man 手冊:man test
分支結構#
if
-
if 用兩個中括號 [[]] 的寫法,更高級,與 TEST 表達式兼容性更好
- 而一個中括號 [ ] 是很多年前的寫法,不推薦,兩個中括號
- 參考Linux Shell 中 ()、(())、[]、[[]]、{} 的作用—— 博客
case
-
分號;;不能沒有!相當於 break,加了 break 也要有
-
默認情況可用 *)
-
case 用的較少,一般用來做菜單,比 if 更美觀
循環結構#
for
-
利用 seq 生成序列
-
利用 ls 的匹配規則
-
for 的兩種形式
-
雙小括號 (()) 中的內容只要符合 C 語言運算規則即可,變量可以不使用變量前綴 $,可以寫 i++,平常不可以用 ++
while
-
同樣適用 test 表達式
-
初始化 num 變量,否則
- 第一次 echo $num 時,$num 是空值,表現為空行
- 當遇到後面的 + 1 時,系統判定它為整數類型,才當做整數用
until
-
與 while 唯一的區別在於:until 寫的是停止條件,while 寫的是循環條件
陣列#
-
陣列賦值【方式①】和調用
-
【常用的陣列操作】還可以輸出陣列元素的下標,見後
-
聲明陣列:declare -a num,方便閱讀,不聲明也可以 [弱類型語言]
-
賦值【方式②、③】
- num[2]=10 num[5]=7 num[100]=3.2.4
- num=(1 a b 10)
-
陣列元素不一定要連續賦值,且可以為任意類型
- 【常用的陣列操作】加!:輸出所有陣列元素對應的下標,可以看出不是連續的
【其它陣列操作】
-
+=:追加
-
unset:刪除陣列,或元素 [通過下標刪除]
-
[PS] 賦值方式③對多個空格也只作一個分隔符
應用
-
可以用來存儲文件名列表
-
【注意】賦值方式③給陣列賦值是以空格作為分隔符,所以如果文件名裡有空格,需要特殊處理
-
【PS】素數篩、線性篩
隨堂練習#
1~100 的偶數和#
-
$[ ] 可用來做整數運算
-
seq 效率稍低
暴力求素數#
-
函數的 return 值
- 通過 $? 獲得,在調用函數後 echo $? 即可,但是 return 值有範圍限制 0~255!
- 通過命令替換符 `` 取到
-
注意對於循環變量 i 的衝突問題:定義局部變量
-
🆒調試程序
- 習慣:適當的 echo 輸出
- 全局調試:bash -x *.sh
- 局部調試:set -x [調試代碼區域] set +x
素數篩#
-
方式一方便操作素數,且輸出時可減少判斷
-
方式二還可以操作合數
【暴力法、素數篩 2 種方法效果比較】求 2~10000 的素數和
- 9.prime.sh 暴力法 —— 10.prime.sh 素數篩
附加知識點#
- .sh 腳本可以直接 bash 或 source 執行,如果要使用./ 需要有可執行權限
- source、sh、bash、./ 有什麼區別——cnblogs
- set -x 可以開啟 shell 調試
- Shell 命令替換:將命令的輸出結果賦值給變量——C 語言中文網
- $() 支持嵌套,反引號 `` 不行
- $() 僅在 Bash 中有效 [似乎 zsh、sh 都支持],而反引號 `` 可在多種 Shell 中使用
- 雙小括號 (()) 中的內容
- 只要符合 C 語言運算規則即可
- 變量可以不使用變量前綴 $
- 可以寫 i++,平常不可以用 ++
- ⭐在 Shell 中,變量還未定義時,其值為空,echo 輸出表現為空行
- ⭐空格問題【嚴格】
- 賦值語句:= 兩側不能有空格
- TEST 表達式相關:[[]] 兩端必須有空格
- 對於變量名 i,如果想將 $i 與_i 拼接,用 $i_i,會去找變量 i_i,所以要用 ${i}_i
Tips#
- 寫 Shell 腳本
- 不要太考慮性能,單純做數學計算效率低
- 為的是快速解決一個問題,用來規劃所有任務的流程
- 做操作前記得加【備份】操作
- 一般是讓系統做事情,難於操作特定的程序做事情
- 程序一般有自己的參數設置,但不具有普適性
- API 一般指服務
- ⭐Shell 風格指南——Google 開源項目風格指南 ——Shell 編程規範
- Shell 腳本多行註解和單行註解的方法—— 博客
:<<!
[要註解的代碼]
!
- 可以了解let—— 菜鳥教程,方便的語法