在這裏我想說的是幾種shell裏的小括號,大括號結構和有括號的變量,命令的用法,以下:shell
1.${var}
2.$(cmd)
3.()和{}
4.${var:-string},${var:+string},${var:=string},${var:?string}
5.$((exp))
6.$(var%pattern),$(var%%pattern),$(var#pattern),$(var##pattern)數組
如今分述以下:bash
1.Shell中變量的原形:${var}
你們常見的變量形式都是$var,如app
$ var=test
$ echo $var
test編輯器
但當你要顯示變量值加隨意的字符(我這裏用AA)時,就會出錯,以下:測試
$ echo $varAA命令行
$orm
這時應該用變量的原形:${var},便是加一個大括號來限定變量名稱的範圍,以下
$ echo ${var}AA
testAA
$進程
以這個特性,咱們能夠很方便地寫一個批量改後綴名的程序,我把它命名爲mymv,程序以下:
#!/bin/baship
tail=$1
for filename in `ls`
do
mv $filename ${filename}.$tail
done
程序須要提供一個後綴名,如c,表示改成後綴爲c的C程序文件,看下面的測試:
$ ls
a b c
$ mymv c
$ ls
a.c b.c c.c
$
看樣子程序運行的很好,但這是不完善的程序,有2個要注意的問題:
A,目錄下沒有子目錄,若是有一個目錄,假設爲dir,則也會被改成dir.c,這顯然不是咱們想要的,應該修正這個程序能識別目錄。
B,沒有幫助對程序的參數進行處理,程序應該足夠友好,在用戶沒有給定後綴名時應能處理,像上面的將直接給文件加上了一個點(.),這顯然也不是咱們想要的。
由於咱們的目的是說明${var},這樣已經足夠了,所以這裏不會再對上面的程序進行修正。
2.命令替換$(cmd)
命令替換$(cmd)和符號`cmd`(注意這不是單引號,在美式鍵盤上,`是ESC下面的那個鍵)有相同之處
$ ls
a b c
$ echo $(ls)
a b c
$ echo `ls`
a b c
咱們來分析一下命令echo $(ls),以便理解所謂命令替換是什麼意思:
shell掃描一遍命令行,發現了$(cmd)結構,便將$(cmd)中的cmd執行一次,獲得其標準輸出,再將此輸出放到原來命令echo $(ls)中的$(ls)位置,即替換了$(ls),再執行echo命令。
以下:
echo $(ls)被替換成了echo a b c
這裏要注意的是$(cmd)中的命令的錯誤輸出是不會被替換的,替換的只是標準輸出:
$ var=$(cat d) ###文件d在當前目錄不存在
cat: d: 沒有那個文件或目錄
$ echo $var
$ ###顯然var變量的值是空的
三、一串的命令執行()和{}
()和{}都是對一串的命令進行執行,但有所區別:
A,()只是對一串命令從新開一個子shell進行執行
B,{}對一串命令在當前shell執行
C,()和{}都是把一串的命令放在括號裏面,而且命令之間用;號隔開
D,()最後一個命令能夠不用分號
E,{}最後一個命令要用分號
F,{}的第一個命令和左括號之間必需要有一個空格
G,()裏的各命令沒必要和括號有空格
H,()和{}中括號裏面的某個命令的重定向隻影響該命令,但括號外的重定向則影響到括號裏的全部命令
咱們來看幾個例子:
$ var=test
$ (var=notest; echo $var) ###變量var值爲notest,此是在子shell中有效
notest
$ echo $var ###父shell中值仍爲test
test
$ { var=notest; echo $var;} ###注意左括號和var之間要有一個空格
notest
$ echo $var ###父shell中的var變量的值變爲了notest
notest
$ { var1=test1;var2=test2;echo $var1>a;echo $var2;} ###輸出test1被重定向到文件a中,
test2 ###而test2輸出則仍輸出到標準輸出中。
$ cat a
test1
$ { var1=test1;var2=test2;echo $var1;echo $var2;}>a ###括號內命令的標準輸出所有被重定向到文件a中
$ cat a
test1
test2
下面是一個腳步例子:
(
echo "1"
echo "2"
) | awk '{print NR,$0}'
4,幾種特殊的替換結構:${var:-string},${var:+string},${var:=string},${var:?string}
A,${var:-string}和${var:=string}
若變量var爲空,則用在命令行中用string來替換${var:-string},不然變量var不爲空時,則用變量var的值來替換${var:-string}
如:
$ echo $newvar
$ echo ${newvar:-a}
a
$ echo $newvar ###變量newvar的值仍然是空,但上一命令行中${newvar:-a}被替換成了a
$ newvar=b
$ echo ${newvar:-a} ###變量newvar的值不爲空時,此命令行中的${newvar:-b}被替換爲$newvar,即b
b
$
對於${var:=string}的替換規則和${var:-string}是同樣的,所不一樣之處是${var:=string}若var爲空時,用string替換${var:=string}的同時,把string賦給變量var:
$ echo $newvar
$ echo ${newvar:=a}
a
$ echo $newvar ###變量newvar被賦值爲a,同時${newvar:=a}被替換成a
a
$ echo ${newvar:=b} ###變量newvar不爲空(其值已被賦爲a),則${newvar:=b}被替換爲newvar的值(即b)
a
$ echo $newvar
a
${var:=string}很經常使用的一種用法是,判斷某個變量是否賦值,沒有的話則給它賦上一個默認值。
如設置默認的編輯器:
PHP 代碼:
echo You use editor: ${EDITOR:=/bin/vi}
B,${var:+string}
${var:+string}的替換規則和上面的相反,即只有當var不是空的時候才替換成string,若var爲空時則不替換或者說是替換成變量 var的值,即空值。(由於變量var此時爲空,因此這兩種說法是等價的)
$ echo $newvar
a
$ echo ${newvar:+b}
b
$ echo $newvar
a
$ newvar=
$ echo ${newvar:+b}
$
C,${var:?string}
替換規則爲:若變量var不爲空,則用變量var的值來替換${var:?string};若變量var爲空,則把string輸出到標準錯誤中,並從腳本中退出。咱們可利用此特性來檢查是否設置了變量的值。
$ newvar=
$ echo ${newvar:?沒有設置newvar的值}
bash: newvar: 沒有設置newvar的值
$ newvar=a
$ echo ${newvar:?沒有設置newvar的值}
a
$
補充擴展:在上面這五種替換結構中string不必定是常值的,可用另一個變量的值或是一種命令的輸出。
$ echo ${var:-`date`}
日 3月 6 02:10:39 CST 2005
$ echo ${var:-$(date)}
日 3月 6 02:11:46 CST 2005
$ a=test
$ echo ${var:-$a}
test
$
5.POSIX標準的擴展計算:$((exp))
這種計算是符合C語言的運算符,也就是說只要符合C的運算符均可用在$((exp)),甚至是三目運算符。
注意:這種擴展計算是整數型的計算,不支持浮點型.如果邏輯判斷,表達式exp爲真則爲1,假則爲0。
$ echo $((3+2))
5
$ echo $((3>2))
1
$ echo $((25<3 ? 2:3))
3
$ echo $var
$ echo $((var=2+3))
5
$ echo $var
5
$ echo $((var++))
5
$ echo $var
6
$
好了,上面的例子足夠了,這也代表了這種擴展運算是很強大的。
6.四種模式匹配替換結構:${var%pattern},${var%%pattern},${var#pattern},${var##pattern}
這四種結構的意義是:${var%pattern}和${var%%pattern}表示從最右邊(即結尾)匹配的,${var#pattern} 和${var##pattern}從最左邊(即開頭)匹配的。其中${var%pattern}和${var#pattern}是最短匹 配,${var%%pattern}和${var##pattern}是最長匹配。只有在pattern中使用了通配符纔能有最長最短的匹配,不然沒有最 長最短匹配之分。
結構中的pattern支持通配符,*表示零個或多個任意字符,?表示零個或一個任意字符,[...]表示匹配中括號裏面的字符,[!...]表示不匹配中括號裏面的字符。
$ var=aabbbccbbdbb
$ echo ${var%b}
aabbbccbbdb
$ echo ${var%%b}
aabbbccbbdb
$ echo ${var#a}
abbbccbbdbb
$ echo ${var##a}
abbbccbbdbb
$ echo ${var%*b}
aabbbccbbdb
$ echo ${var%%*b}
$ echo ${var#a*}
abbbccbbdbb
$ echo ${var##a*}
$
上面是簡單的例舉四種模式匹配替換結構的用法。
•其餘(見man bash中的Parameter Expansion)
${parameter/pattern/string}
Pattern substitution. The pattern is expanded to produce a pat‐
tern just as in pathname expansion. Parameter is expanded and
the longest match of pattern against its value is replaced with
string. If pattern begins with /, all matches of pattern are
replaced with string. Normally only the first match is
replaced. If pattern begins with #, it must match at the begin‐
ning of the expanded value of parameter. If pattern begins with
%, it must match at the end of the expanded value of parameter.
If string is null, matches of pattern are deleted and the / fol‐
lowing pattern may be omitted. If parameter is @ or *, the sub‐
stitution operation is applied to each positional parameter in
turn, and the expansion is the resultant list. If parameter is
an array variable subscripted with @ or *, the substitution
operation is applied to each member of the array in turn, and
the expansion is the resultant list.
(( )) :一對圓括號有兩個地方用到。
1,for循環,
for (( expr1 ; expr2 ; expr3 ))
這裏一對雙括號裏邊的表達式,GNU的文檔指出,expr1支持 Shell Arithmetic;expr2不爲0時,expr3被賦值且語句執行。說的很麻煩,還要花時間搞清楚什麼是Shell Arithmetic。其實一言以蔽之,支持數字條件。好比:
for (( a=0 ; a<10 ; a++ )); do echo $a; done
會輸出 0 1 2 3 (帶換行哦~~~)
2,數學表達
(( )) 和 $(( ))
(( )) 的用法與let同樣,就不用多解釋了吧~~~
$(( ))就是把計算結果拿出來,能夠用在雙引號裏邊,好比:
echo "1+2=$(( 1 + 2 ))"
會輸出 1+2=3
( ):一個圓括號
在for循環裏,跟C語法同樣同樣的。
或者是子程序,返回整個裏邊表達的返回值。裏邊的變量都是局部的,修改不會帶到外邊。舉例子
a=1
(a=3; echo $a)
echo a
結果是 3 1
還有個就是圈數組。。。這個就沒神馬意思了
[ ]:一個方括號,是bash的命令,查man手冊是能夠查到的,跟test同樣,在手冊裏能夠看到不少用法。好比-b -c -gt -eq 什麼的不少,還有用-a表示與,-o表示或等等
[[ ]]:一對方括號是一個方括號的增強版,則是Shell的保留字,裏邊支持了 || && 等等這些符號。通常我喜歡用這個
還有相對複雜的 { }
幾個用處,區分變量,如:
var=abcd; echo ${var}EFG;
這樣,Bash就不會認爲變量是varEFG了
還有用來截取字符串的 ${ }語法比較靈活多變,這裏不作多解釋,你們有興趣能夠本身去搜搜資料,通常我腳本用到的字符串處理,這個都能搞定了。
代碼塊。用來區分代碼的,可是跟( )有個區別,就是在末尾要加上 ;
1.()
在子shell中運行
(a=1);echo $a,結果是空,由於a=1不是在當前shell中運行的(a=1);(echo $a)也是空的。不在同一個子shell中
數組的賦值,見最後的補充
2.(())
表達式計算
a=1;((a++)); echo $a,這時a就是2了。
3.<()和>()
進程代入,能夠把命令的執行結果當成文件同樣讀入
好比comm前通常須要sort,那就能夠這樣comm <(sort 1.lst) <(sort 2.lst)
或者是paste <(cut -t2 file1) <(cut -t1 file1)
,和管道差很少,可是支持多個輸入。
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,而後系統會提示,命令沒找到。
5.$(())
表達式擴展,和(())很類似,可是這個是有點不一樣,$(())不能直接$((b++)),b=1;echo $((++b))這時b等於2,顯示的也是2,b=1;echo $((b++))這時b等於2,顯示的是1.
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。
7.$[]
$(())的過去形式,如今已經不建議使用
8.{}
{1..30} 就是1-30,或者是/{,s}bin/表示/bin/和/sbin/,ab{c,d,e}表示abc、abd、abe
9.${}
變量,用法不少,能夠查看man bash。
先寫這些,之後想到再補充吧。
補充:()同時也是數組的賦值,好比a=(1 3 5),那麼${a[0]}=1;${a[1]}=3;${a[2]}=5,須要注意的是,下標是從0開始的
Shell中的括號有其特殊的用法, 現總結以下:
1. 符號$後的括號
${a} 變量a的值, 在不引發歧義的狀況下能夠省略大括號.
$(cmd) 命令替換, 結果爲shell命令cmd的輸出, 和`cmd`效果相同, 不過某些Shell版本不支持$()形式的命令替換, 如tcsh.
$((exp)) 和`expr exp`效果相同, 計算數學表達式exp的數值, 其中exp只要符合C語言的運算規則便可, 甚至三目運算符和邏輯表達式均可以計算.
2. 多條命令執行
(cmd1;cmd2;cmd3) 新開一個子shell順序執行命令cmd1,cmd2,cmd3, 各命令之間用分號隔開, 最後一個命令後能夠沒有分號.
{ cmd1;cmd2;cmd3;} 在當前shell順序執行命令cmd1,cmd2,cmd3, 各命令之間用分號隔開, 最後一個命令後必須有分號, 第一條命令和左括號之間必須用空格隔開.
對{}和()而言, 括號中的重定向符隻影響該條命令, 而括號外的重定向符影響到括號中的全部命令.
3. 雙括號的特殊用法
(()) 加強括號的用法, 經常使用於算術運算比較. 雙括號中的變量能夠不使用$符號前綴, 只要括號中的表達式符合C語言運算規則, 支持多個表達式用逗號分開.好比能夠直接使用for((i=0;i<5;i++)), 若是不使用雙括號, 則爲for i in `seq 0 4`或者for i in {0..4}.再如能夠直接使用if (($i<5)), 若是不使用雙括號, 則爲if [ $i -lt 5 ]. [[]] 加強方括號用法, 經常使用於字符串的比較. 主要用於條件測試, 雙括號中的表達式可使用&&, ||, <, >等C語言語法.好比能夠直接使用if [[ $a != 1 && $a != 2 ]], 若是不適用雙括號, 則爲if [ $a -ne 1] && [ $a != 2 ]或者if [ $a -ne 1 -a $a != 2 ].