bash cookbook


image

簡介

GNU Bash,又名 Bourne Again Shell。它最初發布於 1989 年,並且輕松成長為 Linux 世界中使用最廣泛的 shell,甚至常見於其他一些類 Unix 系統當中。

shell解析命令行的過程以及eval命令

變量

shell中的變量都是全局變量,函數中的變量需要使用 local 將其變成局部變量,防止污染函數外的變量。

不過從嚴格意義上,Bash沒有變量類型。Bash中的變量,在運行的時候會被展開成其對應的值(字符串)。

靜態變量

在執行過程中不能改變的變量

readonly passwd_file=”/etc/passwd”
readonly group_file=”/etc/group”

變量操作

  1. 大小寫切換

^大寫,,小寫, ~大小寫切換
重復一次只匹配一個字母,重復兩次則應用於所有字母。

HI=HellO
echo "$HI" # HellO
echo ${HI^} # HellO
echo ${HI^^} # HELLO
echo ${HI,} # hellO
echo ${HI,,} # hello
echo ${HI~} # hellO
echo ${HI~~} #hELLo
  1. 替換運算符
${var:-word}    # 如果var存在且非null,返回它的值;否則返回word
${var:=word}    # 如果var存在且非null,返回它的值;否則將word賦值給var,並返回var的值 
${var:?word}    # 如果var存在且非null,返回它的值;否則顯示var:word
${var:+word}    # 如果var存在且非null,返回word;否則返回null

冒號(:)可省略

  1. 模式匹配運算符
${var#pattern}    匹配前綴(最小匹配),並返回余下內容
${var##pattern}   匹配前綴(最大匹配),並返回余下內容
${var%pattern}    匹配結尾(最小匹配),並返回余下內容
${var%%pattern}   匹配結尾(最大匹配),並返回余下內容

pattern為正則表達式匹配

數組

Bash 提供了一維數組變量。任何變量都可以作為一個數組;內建命令 declare 可以顯式地定義數組。數組的大小沒有上限,也沒有限制在連續對成員引用和賦值時有什么要求。數組以整數為下標,從 0 開始。

  1. 定義和初始化數組
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中的數組大小沒有上限,也可以理解為數組是動態的。

  1. 數組的訪問
    數組的任何元素都可以用${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
  1. 數組的刪除
    用unset來進行數組的刪除
unset array[2] # 刪除第三個成員
unset array    # 刪除整個數組
  1. 數組的長度
${#arr[@]}
${#arr[*]}
${#arr}    #錯誤的。這個獲取的是數組第一個成員的長度。
  1. 數組的”切片”操作
    獲取數組的“子串“用${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
  1. 關聯數組
    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

應用

  1. 判斷一個指定的字符串是否在該數組中

    if echo "${ARR[@]}" | grep -w "item_1" &>/dev/null; then
    	echo "Found"
    fi
    

判斷某個元素是否在數組內的幾種方法

四則運算

  1. bash支持的算數運算
+	 - 	* 	/

有些場景中,乘法符號需要轉義

  1. 算數運算實現方式
let a=a+b			  計算結果無法直接獲取,需要賦值后才能使用
var=$[算數表達式]		計算結果可以直接使用,建議使用
var=$((算數表達式))	同上
var=$(expr arg1 arg2 arg3)
  1. 浮點數計算

使用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
  1. 增強型賦值
+= 	-=	 *= 	/= 	%=
let var=var1+=1
let var++	# 自增
let var--	# 自減

條件測試

分類

  • 整數測試
  • 文件測試
  • 字符測試

真返回值為true或者false

條件比較測試表達式有以下三種

[ expression ]
[[ expression ]]
test expression

整數測試

-eq:=
-ne:!=
-gt:>
-lt:<
-ge:>=
-le:<=

文件測試

  1. 存在性測試
-e file	是否存在
-f file	是否為普通文件
-d file	是否為目錄
  1. 權限測試
-r file	指定文件對當前用戶是否可讀
-w file	指定文件對當前用戶是否可寫
-x file	指定文件對當前用戶是否可執行
-u file	當前用戶是否是文件的屬主
-g file	當前用戶是否是文件的屬組
  1. 文件大小測試
-s file	文件存在且非空

字符測試

[[ ]]或者[ ]都可以

  1. 等值比較

=或者==注意:等號兩端要有空格

  1. 不等比較

!=注意:等號兩端要有空格

  1. 是否為空測試
-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 返回狀態碼
  1. 定義

    function func_name(){
        ...函數體...
    }
    
  2. 直接通過函數名調用,函數名后不用加括號。

格式化輸出 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 是指提示符


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM