Shell 參數擴展及各種括號在 Shell 編程中的應用

今天看有人總結了 shell 下的參數擴展,但不是很全,剛好之前整理過放在百度空間,但百度空間目前半死不活的狀況下對 Google 很是不友好,索性一併轉過來方便查閱。php

一、bash 中的大括號參數擴展(Parameter Expansion)

假設咱們定義了一個變量爲:html

file=/dir1/dir2/dir3/my.file.txt

1.1 bash 下的 split 取「數組」的首、尾:

${file#*/}:拿掉第一條 / 及其左邊的字符串:dir1/dir2/dir3/my.file.txt
${file##*/}:拿掉最後一條 / 及其左邊的字符串:my.file.txt
${file#*.}:拿掉第一個 .  及其左邊的字符串:file.txt
${file##*.}:拿掉最後一個 .  及其左邊的字符串:txt
${file%/*}:拿掉最後條 / 及其右邊的字符串:/dir1/dir2/dir3
${file%%/*}:拿掉第一條 / 及其右邊的字符串:(空值)
${file%.*}:拿掉最後一個 .  及其右邊的字符串:/dir1/dir2/dir3/my.file
${file%%.*}:拿掉第一個 .  及其右邊的字符串:/dir1/dir2/dir3/my

Tips:shell

記憶的方法爲:
# 是去掉左邊(在鍵盤上 # 在 $ 之左邊)
% 是去掉右邊(在鍵盤上 % 在 $ 之右邊)
單一符號是最小匹配﹔兩個符號是最大匹配(相似貪婪匹配)。編程

1.2 bash 下的 substring 按字符位置、長度截取

${file:0:5}:提取最左邊的 5 個字節:/dir1
${file:5:5}:提取第 5 個字節右邊的連續 5 個字節:/dir2
${#file}:計算出字符串的長度,/dir1/dir2/dir3/my.file.txt 字符串長度 27
${file: -4}:提取最後四個字符串(空格是爲了不衝突,注意不一樣於echo ${file:-4},也能夠用(-4)代替空格),相似用法(提取前四個字符) ${file:0:4}

1.3 bash 下的 replace 與 replaceAll

咱們也能夠對變量值裏的字符串做替換:segmentfault

${file/dir/path}:將第一個 dir 提換爲 path:/path1/dir2/dir3/my.file.txt
${file//dir/path}:將所有 dir 提換爲 path:/path1/path2/path3/my.file.txt

1.4 bash 下的變量空值檢測與初始化

利用 ${ } 還可針對不一樣的變量狀態賦值(沒設定、空值、非空值):數組

${file-my.file.txt} :假如 $file 沒有設定,則使用 my.file.txt 做傳回值。(空值及非空值時不做處理)
${file:-my.file.txt} :假如 $file 沒有設定或爲空值,則使用 my.file.txt 做傳回值。 (非空值時不做處理)
${file+my.file.txt} :假如 $file 設爲空值或非空值,均使用 my.file.txt 做傳回值。(沒設定時不做處理)
${file:+my.file.txt} :若 $file 爲非空值,則使用 my.file.txt 做傳回值。 (沒設定及空值時不做處理)
${file=my.file.txt} :若 $file 沒設定,則使用 my.file.txt 做傳回值,同時將 $file 賦值爲 my.file.txt 。 (空值及非空值時不做處理)
${file:=my.file.txt} :若 $file 沒設定或爲空值,則使用 my.file.txt 做傳回值,同時將 $file 賦值爲 my.file.txt 。 (非空值時不做處理)
${file?my.file.txt} :若 $file 沒設定,則將 my.file.txt 輸出至 STDERR。 (空值及非空值時不做處理)
${file:?my.file.txt} :若 $file 沒設定或爲空值,則將 my.file.txt 輸出至 STDERR。 (非空值時不做處理)

Tips:
以上的理解在於, 你必定要分清楚 unset 與 null 及 non-null 這三種賦值狀態.
通常而言, : 與 null 有關, 若不帶 : 的話, null 不受影響, 若帶 : 則連 null 也受影響。
而 - 和 = 的區別在因而否把傳回值賦給引用變量,例如:bash

${parameter:-word}     word is only substituted.
${parameter:=word}     word is substituted and assigned to parameter.
root@localhost ~ $ echo "$var"


root@localhost ~ $ echo "${var:-hello}"
hello
root@localhost ~ $ echo "$var"


root@localhost ~ $ echo "${var:=hello}"
hello
root@localhost ~ $ echo "$var"
hello

1.5 bash 下的數組和關聯數組

Bash4中可使用兩種容器。
一種是數組,另外一種是關聯數組,相似於其餘語言中的Map/Hash/Dict。
聲明數組的經常使用語法: declare -a ARY或者ARY=(1 2 3)
聲明關聯數組的惟一語法: declare -A MAP(bash4如下不支持)
賦值的語法:
直接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]}

1.6 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
看來是不行的×_×

二、各種括號在 shell/bash 編程中的應用

上面應該見識到了 shell 中大括號的強大功能,其實 shell 下有不少種括號,不像其它高級語言括號只起到語法和意義的做用,而 shell 下的每種括號除了語法、語義的做用以外,還對 shell 編程起到了功能上的擴展。spa

2.1 () 在子shell中運行
    (a=1);echo $a,結果是空,由於a=1不是在當前shell中運行的(a=1);(echo $a)也是空的。
    小技巧:(cd $path, do something) 可讓不切換當前目錄而在其它目錄乾點別的事兒~
    () 還有個功能是數組的賦值:好比a=(1 3 5),那麼${a[0]}=1;${a[1]}=3;${a[2]}=5,須要注意的是,下標是從0開始的。
    
2.2 (()) 表達式計算
    a=1;((a++));echo $a,這時a就是2了。
    
2.3 <() 和 >() 進程代入,能夠把命令的執行結果當成文件同樣讀入
    好比comm前通常須要sort,那就能夠這樣comm <(sort 1.lst) <(sort 2.lst)
    或者是paste <(cut -t2 file1) <(cut -t1 file1),和管道差很少,可是支持多個輸入。

2.4 $() $(cmd) 執行cmd的結果,
    好比cmd是echo ls,那麼就是執行ls,好比file $(which bash),which bash的結果是/bin/bash,
    因此file $(which bash)等於file /bin/bash。若是你$(ls),並且你的當前目錄下只有a b兩個文件,
    那麼就是執行a b,而後系統會提示,命令沒找到。$() 基本和 `` 等價。
    
2.5 $(()) 表達式擴展,
    和(())很類似,可是這個是有點不一樣,$(())不能直接$((b++)),例如:b=1;echo $((++b))
    這時b等於2,顯示的也是2,b=1; echo $((b++))這時b等於2,顯示的是1.
    
2.6 [] 和 [[]],[] 就是 test,[]和[[]]都是條件表達式,不過[[]]有比[]高的容錯性,
    若是a爲空,那麼[ $a -eq 0 ]會報錯,可是[[ $a -eq 0 ]]不會,因此通常都會使用[[]]或者是
    [ "$a" -eq 0 ],[[]]支持的功能也比 [] 多,好比[[ aaa =~ a{3} ]],[] 還有一種用途,
    若是你的當前目錄下有a1-a9九個文件,你能夠用a[1-9]來替代這九個文件。
    有點須要注意,你不能用a[1-20]來代替a1- a20,必需要a[1-9] a1[0-9] a20。
    可是須要注意的是 [[]] 數字進制轉換的坑~
    
2.7 $[] 是 $(()) 的過去形式,如今已經不建議使用。

2.8 {n..m} {1..30} 就是1-30,或者是/{,s}bin/表示/bin/和/sbin/,ab{c,d,e}表示abc、abd、abe,
    小技巧:文件備份:cp a.sh{,.bak}
    而 { cmd1; cmd2; } 的做用是定義一個命令組,通常用在單行的條件表達式中:
    [[ 1 -eq 2 ]] && echo True || { echo False; echo "Program will exit!"; }
    其實 shell 函數的語法也是它的變體:
    a(){ i=$1; echo $((i++)); echo $((++i)); } && a 1

2.9 ${} 變量的Parameter Expansion,
    用法不少,最基本的 ${var}1,防止變量擴展衝突,具體能夠查看man bash。
    或者參考我以前的博文連接:http://hi.baidu.com/leejun_2005/blog/item/ebfee11a4177ddc1ac6e751d.html

三、bash命令執行流程:.net

執行分爲四大步驟:輸入、解析、擴展和執行。

四、Refer:

[1] shell十三問之大括號參數擴展(Parameter Expansion)

http://hi.baidu.com/leejun_2005/item/138c09343aaddff6e6bb7a49

[2] shell 十三問? 

http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=218853&page=7#

[3] shell/bash編程中各種括號的應用

http://hi.baidu.com/leejun_2005/item/6f9eb7345e5f4f302f20c453

[4] Bash Hackers Wiki Frontpage » Syntax » Parameter expansion

http://wiki.bash-hackers.org/syntax/pe

[5] 玩轉Bash變量

http://segmentfault.com/blog/spacewander/1190000002539169

[6] Bash快速入門指南

http://blog.jobbole.com/85183/

[7] SHELL(bash)腳本編程六:執行流程

http://www.javashuo.com/article/p-arsigipg-bg.html

相關文章
相關標籤/搜索