玩轉 Bash 變數
PS : 注意本文討論的是Bash,而不一定是/bin/sh所連結的那個shell。這裡出現的所有程式碼片段,預設在頂上都新增了#!/bin/bash
。
一門自帶混淆的語言
while (( $# )); do case $1 in -a*) # Error checking [[ ${1#-a} ]] || { echo "bash: ${FUNCNAME[0]}: `$1': missing" "number specifier" 1>&2; return 1; } printf %d "${1#-a}" &> /dev/null || { echo "bash:" "${FUNCNAME[0]}: `$1': invalid number specifier" 1>&2 return 1; } # Assign array of -aN elements [[ "$2" ]] && unset -v "$2" && eval $2=("${@:3:${1#-a}}") && shift $((${1#-a} + 2)) || { echo "bash: ${FUNCNAME[0]}:" "`$1${2+ }$2': missing argument(s)" 1>&2; return 1; } ;; -v) # Assign single value [[ "$2" ]] && unset -v "$2" && eval $2="$3" && shift 3 || { echo "bash: ${FUNCNAME[0]}: $1: missing" "argument(s)" 1>&2; return 1; } ;; *) echo "bash: ${FUNCNAME[0]}: $1: invalid option" 1>&2 return 1 ;; esac done
如果你覺得閱讀上面的Bash程式碼,就像閱讀段子一樣順暢,那麼是時候關掉這個頁面,去做別的更有意義的行為,比如去喝個水什麼的。
如果你覺得上面的Bash程式碼猶如鬼畫符,並且實際生活中不得不面對它,那麼就看下去吧。
Bash變數操作
正式開始正文內容。
想要在一篇文章裡,講述要看懂開篇程式碼所需的所有知識點,這是不自量力的行為。因此,本文將講且僅講Bash中操作變數的方法。所以,即使你看完了這篇文章,你多半還是看不懂開篇的程式碼。
不過看完這篇文章之後,你對Bash的變數操作會有更為深入的認識。而且更重要的是,Bash之於你,不再是怎麼也看不清摸不透。下一次要寫指令碼的時候,你也將更加堅定地下定決心 —— 人生苦短,我用Python/Ruby。
嚴格意義上的Bash變數型別
Bash變數只有兩種型別,字串和陣列。不過從嚴格意義上,Bash沒有變數型別。Bash中的變數,在執行的時候會被展開成其對應的值(字串)。你可以把它看做C/C++中的巨集定義,或者一些模板語言中的佔位符。
一般情況下,變數通過=
賦值,注意=
兩邊不要留空格。有些好孩子,已經養成了符號兩端留空格的習慣,結果當開始寫Bash的時候,他們抓狂了。
要想訪問變數,只需在變數名前面新增$
,直譯器就會對它進行展開。如果該變數並不存在,直譯器會把它展開成“”。
me=spacewander echo $me echo $who
來自命令列的你
作為指令碼語言,第一要義當然是要隨時隨地獲取到命令列輸入啦。
在Bash中,使用$1
可以獲取命令列輸入的第一個引數,$2
可以獲取命令列輸入的第2個引數,$3
可以獲取命令列輸入的第……
你看,$1到$10000的用法就這麼交代完了。Bash還是挺有邏輯的嘛。
順便一提,$0
獲取的指令碼的名字(其實就是其他語言中的第0個引數),$@
獲取所有的引數,$#
獲取引數的數目。記住@
和#
這兩個符號,在Bash這一神祕的符文體系中,前者表示全部引數,後者表示引數的數目。
展開,然後Bomb!
假如Bash變數中含有空白字元,或者含有特殊字元,比如*
,展開後會汙染到外面的字串,結果就是Bomb。
比如
Oops='*' # '*'解釋成所有匹配的檔名 echo $Oops # 所以需要加雙引號括起來 echo "$Oops" # 加單引號會怎樣呢? echo '$Oops'
上面的程式碼值得一試。
另外一種Bomb的可能是,變數後面需要接其它字串,比如$FRUITs
。如果想讓直譯器識別成$FRUIT
變數,而不是$FRUITs
,需要用花括號括起來,像${FRUIT}s
陣列和關聯陣列
Bash中可以使用兩種容器。
一種是陣列,另一種是關聯陣列,類似於其他語言中的Map/Hash/Dict。
宣告陣列的常用語法: declare -a ARY
或者ARY=(1 2 3)
宣告關聯陣列的唯一語法: declare -A MAP
賦值的語法:
直接ARY[N]=VALUE
,N可以是數字索引也可以是鍵。關聯陣列可以使用MAP=([x]=a [y]=b)
進行多項賦值,注意這是賦值的語句而不是宣告。
親測陣列中的索引不一定要按順序來,你可以先給2和3上的元素賦值。(同樣算是弱型別的Javascript也支援這種無厘頭賦值,這算通病麼?)
往現有陣列批量新增元素:
ARY+=(a b c) MAP+=([a]=1 [b]=2)
取值:
${ARY[INDEX]} ${MAP[KEY]}
注意花括號的使用
${A[@]}
展開成所有的變數,而獲取陣列長度使用 ${#A[@]}
切片:
${ARY[@]:N:M}
N是offset而M是length
返回索引,相當於keys():
${!MAP[@]}
試試下面的程式碼:
declare -a ARY declare -A MAP MAP+=([a]=1 [b]=2) ARY+=(a b c) echo ${ARY[1]} echo ${MAP[a]} echo "${ARY[@]}" echo "${MAP[@]}" echo "${ARY[@]:0:1}" echo ${#ARY[@]} echo "${!MAP[@]}" ARY[4]=a echo ${ARY[@]} echo ${ARY[3]}
變數(字串)變換
Bash中的變數變換,大體是${變數[操作符]}的形式
大小寫變換
HI=HellO echo "$HI" # HellO echo ${HI^} # HellO echo ${HI^^} # HELLO echo ${HI,} # hellO echo ${HI,,} # hello echo ${HI~} # hellO echo ${HI~~} #hELLo
^
大寫,,
小寫, ~
大小寫切換
重複一次只修改首字母,重複兩次則應用於所有字母。
混著用會怎樣?
echo ${HI^,^} # HellO
看來是不行的×_×
移除匹配的字串
%xx
從後往前,開始匹配,移除匹配的內容
%%xx
跟上面的差不多,不過這是貪婪匹配
#xx
從前往後,開始匹配,移除匹配的內容
##xx
跟上面的差不多,不過這是貪婪匹配
這個比較難理解,不過看下面幾個例子應該能明白了。
FILENAME=/home/spacewander/param.sh echo ${FILENAME%/*} # /home/spacewander echo ${FILENAME%%/*} # echo ${FILENAME#*/} # home/spacewander/param.sh echo ${FILENAME##*/} # param.sh
查詢並替換
/MATCH/VALUE
替換第一個匹配的內容。
//MATCH/VALUE
替換匹配的內容
echo ${FILENAME/home/office} # /office/spacewander/param.sh echo ${FILENAME//s/S} # /home/Spacewander/param.Sh
其它字串操作
獲取變數(字串)長度:${#FILENAME}
字串切片:跟陣列切片是同樣的語法,${STR:offset:len}
TEXT=這個程式充滿了BUG! echo ${TEXT:0:8} echo ${TEXT:4} # 你還可以使用負數作為offset,這時候就是從後往前算起。注意負數要用括號括起來,避免衝突。 echo ${TEXT:(-4)}
關於變數,其它的內容
Bash中有一項特性,你可以方便地檢查某個變數是否設定了,如果沒有設定,就賦予一個預設值。尤其在處理環境變數的時候,這項特性會讓你感到欣慰。
語法是${VAR:=VALUE}
或者${VAR:=VALUE}
。此外,還有一個相似的語法,${VAR:=VALUE}
和${VAR:=VALUE}
。
下面展示下兩者的區別
# expand to default variable echo ${NULL-"Not null"} # Not null echo ${NULL} # # set default variable echo ${NIL="Not nil"} # Not nil echo ${NIL} # Not nil
可以看出,前者只是當變數不存在時,展開成指定的值。而後者在變數不存在時,將變數的值設定為指定值。
最後介紹一個,當目標變數不存在時,指定報錯資訊的語法。
echo ${TARGET?Not Found} # 當$TARGET不存在時,顯示TARGET: Not Found,並結束程式。
相關文章
- shell Bash變數變數
- Bash變數和引數變數
- Linux 程式設計之Bash中的變數(轉)Linux程式設計變數
- shell程式設計–bash變數程式設計變數
- 詳解Linux bash變數Linux變數
- Bash 中的環境變數變數
- shell程式設計Bash中對變數的操作方法談(轉)程式設計變數
- shell程式設計–bash變數介紹程式設計變數
- Linux中bash shell環境變數Linux變數
- Bash 中的 _ 是不是環境變數變數
- BASH_SUBSHELL 變數不生效的情況變數
- 在JavaScript中也玩變數型別強行轉換JavaScript變數型別
- Bash: export - 設定或顯示環境變數Export變數
- linux中BASH變數的設定規則Linux變數
- Linux基本命令學習之五:bash 變數Linux變數
- java 變數(轉)Java變數
- 微課|玩轉Python輕鬆過二級(2.1.1):常量與變數Python變數
- Bash 中 SHLVL 變數為 1000 的時候變數
- SHLVL 和 BASH_SUBSHELL 兩個變數的區別變數
- Bash 中為 _ 變數賦空值的三個場景變數
- 資料庫效能大揭秘:玩轉MySQL監控指標狀態變數資料庫MySql指標變數
- linux系統環境變數.bash_profile/bashrc檔案Linux變數
- Bash 是如何從環境變數中匯入函式的變數函式
- linux登入bash shell環境執行環境變數Linux變數
- bash(詳解)(轉)
- 使.bash_profile 檔案中環境變數馬上生效的命令變數
- 變數型別轉換變數型別
- Mac-每次都要執行source ~/.bash_profile環境變數才生效Mac變數
- [20180131]bash變數替換與擷取.txt變數
- shell簡介之bash程式設計之引數說明(轉)程式設計
- 玩轉雲端 | 天翼雲電腦的百變玩法
- Unix的環境變數(轉)變數
- Unix的環境變數 (轉)變數
- 設定環境變數(轉)變數
- bash入門基礎(轉)
- bash 程式設計指南(轉)程式設計
- [20200217]bash顯示path環境變數.txt變數
- [20180129]bash顯示path環境變數.txt變數