
簡介
GNU Bash,又名 Bourne Again Shell。它最初發布於 1989 年,並且輕松成長為 Linux 世界中使用最廣泛的 shell,甚至常見於其他一些類 Unix 系統當中。
變量
shell中的變量都是全局變量,函數中的變量需要使用 local
將其變成局部變量,防止污染函數外的變量。
不過從嚴格意義上,Bash沒有變量類型。Bash中的變量,在運行的時候會被展開成其對應的值(字符串)。
靜態變量
在執行過程中不能改變的變量
readonly passwd_file=”/etc/passwd”
readonly group_file=”/etc/group”
變量操作
- 大小寫切換
^大寫,,小寫, ~大小寫切換
重復一次只匹配一個字母,重復兩次則應用於所有字母。
HI=HellO
echo "$HI" # HellO
echo ${HI^} # HellO
echo ${HI^^} # HELLO
echo ${HI,} # hellO
echo ${HI,,} # hello
echo ${HI~} # hellO
echo ${HI~~} #hELLo
- 替換運算符
${var:-word} # 如果var存在且非null,返回它的值;否則返回word
${var:=word} # 如果var存在且非null,返回它的值;否則將word賦值給var,並返回var的值
${var:?word} # 如果var存在且非null,返回它的值;否則顯示var:word
${var:+word} # 如果var存在且非null,返回word;否則返回null
冒號(:)可省略
- 模式匹配運算符
${var#pattern} 匹配前綴(最小匹配),並返回余下內容
${var##pattern} 匹配前綴(最大匹配),並返回余下內容
${var%pattern} 匹配結尾(最小匹配),並返回余下內容
${var%%pattern} 匹配結尾(最大匹配),並返回余下內容
pattern為正則表達式匹配
數組
Bash 提供了一維數組變量。任何變量都可以作為一個數組;內建命令 declare 可以顯式地定義數組。數組的大小沒有上限,也沒有限制在連續對成員引用和賦值時有什么要求。數組以整數為下標,從 0 開始。
- 定義和初始化數組
declare -a array # 顯示聲明了數組array
array[key]=value # array[0]=one
array=(value1 value2...) # value的形式都是[subscript]=string,下標和等號可以省略,示例如下。
array=([0]=value1 [2]=value3 [3]=value[4])
# 關聯數組的另一種定義方式
mydict=(["name"]=guess ["old"]=18 ["favourite"]=coconut ["my description"]="I am a student")
從上面來看數組的定義也是非常靈活多變的,能夠滿足我們大部分的需求,跟其其它語言最大的區別就是shell中的數組大小沒有上限,也可以理解為數組是動態的。
- 數組的訪問
數組的任何元素都可以用${array[subscript]}
來引用,花括號是必須的,以避免和路徑擴展沖突。
如果 subscript 是@
或是*
,它擴展為array的所有成員。
這兩種下標只有在雙引號中才不同。在雙引號中,"${name[*]}"
擴展為一個詞,由所有數組成員的值組成,用特殊變量IFS的第一個字符分隔數組成員;"${array[@]}"
將array的每個成員擴展為一個詞。 如果數組沒有成員,${name[@]}
擴展為空串。
示例--"${name[*]}"
和"${array[@]}"
的不同
#!/bin/bash
arr=("one" "two")
for i in "${arr[*]}"
do
echo ${i}
done
for i in "${arr[@]}"
do
echo ${i}
done
輸出如下
one two
one
two
- 數組的刪除
用unset來進行數組的刪除
unset array[2] # 刪除第三個成員
unset array # 刪除整個數組
- 數組的長度
${#arr[@]}
${#arr[*]}
${#arr} #錯誤的。這個獲取的是數組第一個成員的長度。
- 數組的”切片”操作
獲取數組的“子串“用${arr[@]:n:m}
來表示,如果沒有:m那么就獲取從下標n開始到最后一個元素的“字串“,示例如下:
#!/bin/bash
arr=(one two three four)
echo ${arr[@]:2}
echo ${arr[@]:1:3}
echo ${arr[@]:0}
輸出如下
three four
two three four
one two three four
- 關聯數組
shell中還可以聲明一個關聯數組,普通數組只能使用整數作為數組的索引,而關聯數組則使用字符串作為數組的索引。這個關聯數組有點像其它語言中的字典。在mac下的bash 中的declare不含這個-A
這個參數。
#!/bin/bash
declare -A array
array["age"]=29
array["name"]=Yang
# 輸出數組的value
echo "${array[@]}"
# 遍歷數組的值
for a in "${array[@]}"; do
echo "${a}"
done
# 通過下標獲取元素值
echo "${array[age]}"
# 輸出數組的key
echo "${!array[@]}"
# 遍歷數組的key
for a in "${!array[@]}"; do
echo "${a}"
done
輸出
Yang 29
Yang
29
29
name age
name
應用
-
判斷一個指定的字符串是否在該數組中
if echo "${ARR[@]}" | grep -w "item_1" &>/dev/null; then echo "Found" fi
四則運算
- bash支持的算數運算
+ - * /
有些場景中,乘法符號需要轉義
- 算數運算實現方式
let a=a+b 計算結果無法直接獲取,需要賦值后才能使用
var=$[算數表達式] 計算結果可以直接使用,建議使用
var=$((算數表達式)) 同上
var=$(expr arg1 arg2 arg3)
- 浮點數計算
使用shell
內置命令bc
# 進制轉換
echo "obase=2; ibase=2; 1+1" | bc
# 保留精度
echo "scale=2;1/2" | bc
# 多行計算
# v1=$(bc << EOF
> v2=1
> v3=2
> v2+v3
> EOF
> )
# echo $v1
3
- 增強型賦值
+= -= *= /= %=
let var=var1+=1
let var++ # 自增
let var-- # 自減
條件測試
分類
- 整數測試
- 文件測試
- 字符測試
真返回值為true或者false
條件比較測試表達式有以下三種
[ expression ]
[[ expression ]]
test expression
整數測試
-eq:=
-ne:!=
-gt:>
-lt:<
-ge:>=
-le:<=
文件測試
- 存在性測試
-e file 是否存在
-f file 是否為普通文件
-d file 是否為目錄
- 權限測試
-r file 指定文件對當前用戶是否可讀
-w file 指定文件對當前用戶是否可寫
-x file 指定文件對當前用戶是否可執行
-u file 當前用戶是否是文件的屬主
-g file 當前用戶是否是文件的屬組
- 文件大小測試
-s file 文件存在且非空
字符測試
[[ ]]
或者[ ]
都可以
- 等值比較
=
或者==
,注意:等號兩端要有空格
- 不等比較
!=
,注意:等號兩端要有空格
- 是否為空測試
-z string:測試字符串是否為空,空為真;
-n string:測試字符串是否不為空,不空為真;
~= 左側的字符串能否被右側的PATTERN所匹配
組合條件測試
主要分兩類
COMMAND1 && COMMAND2
COMMAND1 || COMMAND2
! COMMAND1
[ EXPRESSION1 -a EXPRESSION2 ]
[ EXPRESSION1 -o EXPRESSION2 ]
[ ! EXPRESSION1 ]
示例,傳遞一個用戶名參數給腳本,判斷此用戶的用戶名跟其基本組的組名是否一致,並將結果顯示出來。
#!/bin/bash
if [ $# -ne 1 ]; then
echo "Please enter a argument."
exit 1
elif ! id $1 &> /dev/null; then
echo "No such user."
exit 2
elif [ $1 == $(id $1 -g -n) ]; then
echo "Same."
else
echo "Diffrent."
fi
選擇語句
case SWITCH in
value1)
statement1
...
;;
value2)
statement2
...
;;
*)
statement3
...
;;
esac
循環語句
循環需要有進入條件和退出條件
for--有限循環
# 形式1
for 變量 in 列表;do
循環體
done
# 形式2
for (( expr1 ; expr2 ; expr3 )); do
循環體
done
生成整數列表
{1..100}
`seq [起始數] [步進長度] 結束數`
示例
for i in `seq 1 $a`; do echo $i; done
while--無線循環
條件滿足則執行循環
while CONDITION; do
循環體
done
示例
while的特殊用法一,死循環
while :; do
循環體
done
while的特殊用法二,按行讀取文件
while read LINE; do
循環體
done < /PATH/TO/SOMEFILE
until
滿足條件則結束循環
until CONDITION; do
循環體
done
continue
提前結束本輪循環,進入下一輪循環
函數
- 通過位置傳遞參數
- 通過 echo 返回值
- 通過return 返回狀態碼
-
定義
function func_name(){ ...函數體... }
-
直接通過函數名調用,函數名后不用加括號。
格式化輸出 echo printf
echo
-n 不換行輸出
-e 支持擴展
printf
使用printf可以輸出更規則更格式化的結果。它引用於C語言的printf命令,但是有些許區別。
printf可以指定字符串的寬度、實現左對齊(使用減符號-)、右對齊(默認的)、格式化小數輸出等。
使用printf最需要注意的兩點是:
- printf默認不在結尾加換行符,它不像echo一樣,所以要手動加“\n”換號;
- printf只是格式化輸出,不會改變任何結果,所以在格式化浮點數的輸出時,浮點數結果是不變的,僅僅只是改變了顯示的結果。
> printf "%-5s %-10s %-4s\n" No Name Mark # 三個%分別對應后面的三個參數
> printf "%-5s %-10s %-4.2f\n" 1 Sarath 80.34 # 減號“-”表示左對齊
> printf "%-5s %-10s %-4.2f\n" 2 James 90.998 # 5s表示第一個參數占用5個字符
> printf "%-5s %-10s %-4.2f\n" 3 Jeff 77.564
其他
位置參數 $@ $* $#
$*
表示從1開始所有位置的參數,如果擴展發生在雙引號內,即"$*"
,則擴展包含每個參數值的單詞,每個參數值用特殊表量IFS的第一個字符分割;也就是說,"$*"
等價於"$1c$2c..."
,其中,c時特殊變量IFS的第一個字符。如果變量IFS沒有定義,則參數之間默認用空格分割。
$@
也擴展為從1開始的所有位置參數。但當它的擴展發生在雙引號內時,每個參數都擴展為分割的單詞。即:"$@"
等價於"$1"、"$2" ...
。參數@與*之間的區別會在for循環中體現出來。循環時用 $@
。
如果命令運行失敗讓腳本退出執行
set -o errexit
set -e
若有用未設置的變量即讓腳本退出執行
set -o nounset
set -u
BASH中用 read 實現“按任意鍵繼續”
read -s -n1 -p "按任意鍵繼續 ... "
參數說明
-s 指輸入的字符屏幕上不可件,應該說可見,但由於和終端的背景色相同,故不可見
-n 1 表示僅接收1個字符,按回車鍵也屬於一個字符
-p 是指提示符