Bash指令碼15分鐘高階教程

2022-05-21 20:30:13 字數 4738 閱讀 8979

這裡的技術技巧最初是來自谷歌的「testing on the toilet」 (tott)。這裡是乙個修訂和擴增版本。

我的所有bash指令碼都以下面幾句為開場白:

#!/bin/bash

set -o nounset

set -o errexit

這樣做會避免兩種常見的問題:

引用未定義的變數(預設值為「」)

執行失敗的命令被忽略

需要注意的是,有些linux命令的某些引數可以強制忽略發生的錯誤,例如「mkdir -p」 和 「rm -f」。

在bash裡你可以定義函式,它們就跟其它命令一樣,可以隨意的使用;它們能讓你的指令碼更具可讀性:

extractbashcomments()  

cat myscript.sh | extractbashcomments | wc

comments=$(extractbashcomments < myscript.sh)

還有一些例子:

sumlines()  + $))

done

echo $

} sumlines < data_one_number_per_line.txt

log() $@" >&2

} log "info" "a message"

盡可能的把你的bash**移入到函式裡,僅把全域性變數、常量和對「main」呼叫的語句放在最外層。

bash裡可以對變數進行有限的註解。最重要的兩個註解是:

local(函式內部變數)

readonly(唯讀變數)

# a useful idiom: default_val can be overwritten

# with an environment variable of the same name

readonly default_val=$

myfunc()

...}

這樣,你可以將乙個以前不是唯讀變數的變數宣告成唯讀變數:

x=5

x=6readonly x

x=7 # failure

盡量對你bash指令碼裡的所有變數使用localreadonly進行註解。

反單引號很難看,在有些字型裡跟正單引號很相似。$()能夠內嵌使用,而且避免了轉義符的麻煩。

# both commands below print out: a-b-c-d

echo "a-`echo b-\`echo c-\\\`echo d\\\`\``"

echo "a-$(echo b-$(echo c-$(echo d)))"

使用能避免像異常的副檔名之類的問題,而且能帶來很多語法上的改進,而且還增加了很多新功能:

操作符	功能說明

|| 邏輯or(僅雙中括號裡使用)

&& 邏輯and(僅雙中括號裡使用)

< 字串比較(雙中括號裡不需要轉移)

-lt 數字比較

= 字串相等

== 以globbing方式進行字串比較(僅雙中括號裡使用,參考下文)

=~ 用正規表示式進行字串比較(僅雙中括號裡使用,參考下文)

-n 非空字串

-z 空字串

-eq 數字相等

-ne 數字不等

[ "$" \> "a" -o $ \< "m" ]
[[ "$" > "a" && "$" < "m"  ]]
使用雙中括號帶來的好處用下面幾個例子最能表現:

t="abc123"

[[ "$t" == abc* ]] # true (globbing比較)

[[ "$t" == "abc*" ]] # false (字面比較)

[[ "$t" =~ [abc]+[123]+ ]] # true (正規表示式比較)

[[ "$t" =~ "abc*" ]] # false (字面比較)

注意,從bash 3.2版開始,正規表示式和globbing表示式都不能用引號包裹。如果你的表示式裡有空格,你可以把它儲存到乙個變數裡:

r="a b+"

[[ "a bbb" =~ $r ]] # true

按globbing方式的字串比較也可以用到case語句中:

case $t in

abc*) ;;

esac

bash裡有各種各樣操作字串的方式,很多都是不可取的。

基本使用者

f="path1/path2/file.ext"  

len="$" # = 20 (字串長度)

# 切片操作: $ or $

slice1="$" # = "path2/file.ext"

slice2="$" # = "path2"

slice3="$" # = "file.ext"(注意:"-"前有空格)

pos=6

len=5

slice4="$:$}" # = "path2"

替換操作(使用globbing)
f="path1/path2/file.ext"  

single_subst="$" # = "x/path2/file.ext"

global_subst="$" # = "x/x/file.ext"

# 字串拆分

readonly dir_sep="/"

array=($/ })

second_dir="$" # = path2

刪除頭部或尾部(使用globbing)
f="path1/path2/file.ext" 

# 刪除字串頭部

extension="$" # = "ext"

# 以貪婪匹配方式刪除字串頭部

filename="$" # = "file.ext"

# 刪除字串尾部

dirname="$" # = "path1/path2"

# 以貪婪匹配方式刪除字串尾部

root="$" # = "path1"

有些命令需要以檔名為引數,這樣一來就不能使用管道。這個時候就顯出用處了,它可以接受乙個命令,並把它轉換成可以當成檔名之類的什麼東西:

diff

還有乙個非常有用處的是」here documents」,它能讓你在標準輸入上輸入多行字串。下面的』marker』可以替換成任何字詞。

# 任何字詞都可以當作分界符

command << marker

...$

$(cmd)

...marker

如果文字裡沒有內嵌變數替換操作,你可以把第乙個marker用單引號包起來:

command << 'marker'

...$ (dollar sign) is passed through verbatim.

...marker

變數	說明

$0 指令碼名稱

$n 傳給指令碼/函式的第n個引數

$$ 指令碼的pid

$! 上乙個被執行的命令的pid(後台執行的程序)

$? 上乙個命令的退出狀態(管道命令使用$)

$# 傳遞給指令碼/函式的引數個數

$@ 傳遞給指令碼/函式的所有引數(識別每個引數)

$* 傳遞給指令碼/函式的所有引數(把所有引數當成乙個字串)

提示

使用\(*很少是正確的選擇。

\)@能夠處理空格引數,而且引數間的空格也能正確的處理。

使用\(@時應該用雙引號括起來,像」\)@」這樣。

對指令碼進行語法檢查:

bash -n myscript.sh
跟蹤指令碼裡每個命令的執行:

bash -v myscripts.sh
跟蹤指令碼裡每個命令的執行並附加擴充資訊:

bash -x myscript.sh
你可以在指令碼頭部使用set -o verboseset -o xtrace來永久指定-v-o。當在遠端機器上執行指令碼時,這樣做非常有用,用它來輸出遠端資訊。

這個時候,你應該考慮一種指令碼語言,比如python或ruby。

15分鐘了解Phoenix

以下部分翻譯自 phoenix為hbase穿上一層sql的外衣。所以你可以使用標準的jdbc api來建立表 插入資料 查詢hbase中的資料,而不是使用常規的hbase客戶端api。不會。跟原生的hbase客戶端相比,phoenix效能一樣好甚至更好,主要通過以下方式 除此之外,我們還做了一些工作...

15分鐘了解TiDB

2019年07月13日 22 21 49 d guco 閱讀數 77341 由於目前的專案把mysql換成了tidb,所以特意來了解下tidb。其實也不能說換,由於tidb和mysql幾乎完全相容,所以我們的程式沒有任何改動就完成了資料庫從mysql到tidb的轉換,tidb 是乙個分布式 news...

Git五分鐘教程

使用git前,需要先建立乙個倉庫 repository 您可以使用乙個已經存在的目錄作為git倉庫或建立乙個空目錄。git initgit init newrepo從現在開始,我們將假設您在git倉庫根目錄下,除非另有說明。我們有乙個倉庫,但什麼也沒有,可以使用add命令新增檔案。git add f...