shell中各種括號(hào)的使用方法(摘自網(wǎng)絡(luò))
在這里我想說(shuō)的是幾種shell里的小括號(hào),大括號(hào)結(jié)構(gòu)和有括號(hào)的變量,命令的用法辆床,如下:
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)
現(xiàn)在分述如下:
1.Shell中變量的原形:${var}
大家常見(jiàn)的變量形式都是$var,如
$ var=test
$ echo $var
test
但當(dāng)你要顯示變量值加隨意的字符(我這里用AA)時(shí)贺喝,就會(huì)出錯(cuò),如下:
$ echo $varAA
$
這時(shí)應(yīng)該用變量的原形:${var},即是加一個(gè)大括號(hào)來(lái)限定變量名稱(chēng)的范圍,如下
$ echo ${var}AA
testAA
$
以這個(gè)特性剔宪,我們可以很方便地寫(xiě)一個(gè)批量改后綴名的程序,我把它命名為mymv壹无,程序如下:
#!/bin/bash
tail=$1
for filename in `ls`
do
mv $filename ${filename}.$tail
done
程序需要提供一個(gè)后綴名葱绒,如c,表示改為后綴為c的C程序文件格遭,看下面的測(cè)試:
$ ls
a b c
$ mymv c
$ ls
a.c b.c c.c
$
看樣子程序運(yùn)行的很好泼差,但這是不完善的程序涮因,有2個(gè)要注意的問(wèn)題:
A,目錄下沒(méi)有子目錄,如果有一個(gè)目錄卸察,假設(shè)為dir,則也會(huì)被改為dir.c璧微,這顯然不是我們想要的作箍,應(yīng)該修正這個(gè)程序能識(shí)別目錄。
B,沒(méi)有幫助對(duì)程序的參數(shù)進(jìn)行處理前硫,程序應(yīng)該足夠友好胞得,在用戶沒(méi)有給定后綴名時(shí)應(yīng)能處理,像上面的將直接給文件加上了一個(gè)點(diǎn)(.),這顯然也不是我們想要的屹电。
因?yàn)槲覀兊哪康氖钦f(shuō)明${var}阶剑,這樣已經(jīng)足夠了,因此這里不會(huì)再對(duì)上面的程序進(jìn)行修正危号。
2.命令替換$(cmd)
命令替換$(cmd)和符號(hào)`cmd`(注意這不是單引號(hào)牧愁,在美式鍵盤(pán)上,`是ESC下面的那個(gè)鍵)有相同之處
$ ls
a b c
$ echo $(ls)
a b c
$ echo `ls`
a b c
我們來(lái)分析一下命令echo $(ls)外莲,以便理解所謂命令替換是什么意思:
shell掃描一遍命令行猪半,發(fā)現(xiàn)了$(cmd)結(jié)構(gòu),便將$(cmd)中的cmd執(zhí)行一次偷线,得到其標(biāo)準(zhǔn)輸出磨确,再將此輸出放到原來(lái)命令echo $(ls)中的$(ls)位置,即替換了$(ls),再執(zhí)行echo命令声邦。
如下:
echo $(ls)被替換成了echo a b c
這里要注意的是$(cmd)中的命令的錯(cuò)誤輸出是不會(huì)被替換的乏奥,替換的只是標(biāo)準(zhǔn)輸出:
$ var=$(cat d) ###文件d在當(dāng)前目錄不存在
cat: d: 沒(méi)有那個(gè)文件或目錄
$ echo $var
$ ###顯然var變量的值是空的
3、一串的命令執(zhí)行()和{}
()和{}都是對(duì)一串的命令進(jìn)行執(zhí)行翔忽,但有所區(qū)別:
A,()只是對(duì)一串命令重新開(kāi)一個(gè)子shell進(jìn)行執(zhí)行
B,{}對(duì)一串命令在當(dāng)前shell執(zhí)行
C,()和{}都是把一串的命令放在括號(hào)里面英融,并且命令之間用;號(hào)隔開(kāi)
D,()最后一個(gè)命令可以不用分號(hào)
E,{}最后一個(gè)命令要用分號(hào)
F,{}的第一個(gè)命令和左括號(hào)之間必須要有一個(gè)空格
G,()里的各命令不必和括號(hào)有空格
H,()和{}中括號(hào)里面的某個(gè)命令的重定向只影響該命令,但括號(hào)外的重定向則影響到括號(hào)里的所有命令
我們來(lái)看幾個(gè)例子:
$ var=test
$ (var=notest; echo $var) ###變量var值為notest歇式,此是在子shell中有效
notest
$ echo $var ###父shell中值仍為test
test
$ { var=notest; echo $var;} ###注意左括號(hào)和var之間要有一個(gè)空格
notest
$ echo $var ###父shell中的var變量的值變?yōu)榱薾otest
notest
$ { var1=test1;var2=test2;echo $var1>a;echo $var2;} ###輸出test1被重定向到文件a中驶悟,
test2 ###而test2輸出則仍輸出到標(biāo)準(zhǔn)輸出中。
$ cat a
test1
$ { var1=test1;var2=test2;echo $var1;echo $var2;}>a ###括號(hào)內(nèi)命令的標(biāo)準(zhǔn)輸出全部被重定向到文件a中
$ cat a
test1
test2
下面是一個(gè)腳步例子:
(
echo "1"
echo "2"
) | awk '{print NR,$0}'
4,幾種特殊的替換結(jié)構(gòu):${var:-string},${var:+string},${var:=string},${var:?string}
A,${var:-string}和${var:=string}
若變量var為空材失,則用在命令行中用string來(lái)替換${var:-string}痕鳍,否則變量var不為空時(shí),則用變量var的值來(lái)替換${var:-string}
如:
$ echo $newvar
$ echo ${newvar:-a}
a
$ echo $newvar ###變量newvar的值仍然是空龙巨,但上一命令行中${newvar:-a}被替換成了a
$ newvar=b
$ echo ${newvar:-a} ###變量newvar的值不為空時(shí)笼呆,此命令行中的${newvar:-b}被替換為$newvar,即b
b
$
對(duì)于${var:=string}的替換規(guī)則和${var:-string}是一樣的旨别,所不同之處是${var:=string}若var為空時(shí)诗赌,用string替換${var:=string}的同時(shí),把string賦給變量var:
$ echo $newvar
$ echo ${newvar:=a}
a
$ echo $newvar ###變量newvar被賦值為a秸弛,同時(shí)${newvar:=a}被替換成a
a
$ echo ${newvar:=b} ###變量newvar不為空(其值已被賦為a)铭若,則${newvar:=b}被替換為newvar的值(即b)
a
$ echo $newvar
a
${var:=string}很常用的一種用法是洪碳,判斷某個(gè)變量是否賦值,沒(méi)有的話則給它賦上一個(gè)默認(rèn)值叼屠。
如設(shè)置默認(rèn)的編輯器:
PHP 代碼:
echo You use editor: ${EDITOR:=/bin/vi}
B,${var:+string}
${var:+string}的替換規(guī)則和上面的相反瞳腌,即只有當(dāng)var不是空的時(shí)候才替換成string,若var為空時(shí)則不替換或者說(shuō)是替換成變量 var的值镜雨,即空值嫂侍。(因?yàn)樽兞縱ar此時(shí)為空,所以這兩種說(shuō)法是等價(jià)的)
$ echo $newvar
a
$ echo ${newvar:+b}
b
$ echo $newvar
a
$ newvar=
$ echo ${newvar:+b}
$
C,${var:?string}
替換規(guī)則為:若變量var不為空荚坞,則用變量var的值來(lái)替換${var:?string}挑宠;若變量var為空,則把string輸出到標(biāo)準(zhǔn)錯(cuò)誤中西剥,并從腳本中退出痹栖。我們可利用此特性來(lái)檢查是否設(shè)置了變量的值。
$ newvar=
$ echo ${newvar:?沒(méi)有設(shè)置newvar的值}
bash: newvar: 沒(méi)有設(shè)置newvar的值
$ newvar=a
$ echo ${newvar:?沒(méi)有設(shè)置newvar的值}
a
$
補(bǔ)充擴(kuò)展:在上面這五種替換結(jié)構(gòu)中string不一定是常值的瞭空,可用另外一個(gè)變量的值或是一種命令的輸出揪阿。
$ 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標(biāo)準(zhǔn)的擴(kuò)展計(jì)算:$((exp))
這種計(jì)算是符合C語(yǔ)言的運(yùn)算符,也就是說(shuō)只要符合C的運(yùn)算符都可用在$((exp))咆畏,甚至是三目運(yùn)算符南捂。
注意:這種擴(kuò)展計(jì)算是整數(shù)型的計(jì)算,不支持浮點(diǎn)型.若是邏輯判斷旧找,表達(dá)式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
$
好了,上面的例子足夠了钮蛛,這也表明了這種擴(kuò)展運(yùn)算是很強(qiáng)大的鞭缭。
6.四種模式匹配替換結(jié)構(gòu):${var%pattern},${var%%pattern},${var#pattern},${var##pattern}
這四種結(jié)構(gòu)的意義是:${var%pattern}和${var%%pattern}表示從最右邊(即結(jié)尾)匹配的,${var#pattern} 和${var##pattern}從最左邊(即開(kāi)頭)匹配的魏颓。其中${var%pattern}和${var#pattern}是最短匹 配岭辣,${var%%pattern}和${var##pattern}是最長(zhǎng)匹配。只有在pattern中使用了通配符才能有最長(zhǎng)最短的匹配甸饱,否則沒(méi)有最 長(zhǎng)最短匹配之分沦童。
結(jié)構(gòu)中的pattern支持通配符,*表示零個(gè)或多個(gè)任意字符叹话,?表示零個(gè)或一個(gè)任意字符偷遗,[...]表示匹配中括號(hào)里面的字符,[!...]表示不匹配中括號(hào)里面的字符驼壶。
$ 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*}
$
上面是簡(jiǎn)單的例舉四種模式匹配替換結(jié)構(gòu)的用法氏豌。
?其他(見(jiàn)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.
(( )) :一對(duì)圓括號(hào)有兩個(gè)地方用到。
1热凹,for循環(huán)泵喘,
for (( expr1 ; expr2 ; expr3 ))
這里一對(duì)雙括號(hào)里邊的表達(dá)式瞭吃,GNU的文檔指出,expr1支持 Shell Arithmetic涣旨;expr2不為0時(shí),expr3被賦值且語(yǔ)句執(zhí)行股冗。說(shuō)的很麻煩霹陡,還要花時(shí)間搞清楚什么是Shell Arithmetic。其實(shí)一言以蔽之止状,支持?jǐn)?shù)字條件烹棉。比如:
for (( a=0 ; a<10 ; a++ )); do echo $a; done
會(huì)輸出 0 1 2 3 (帶換行哦~~~)
2,數(shù)學(xué)表達(dá)
(( )) 和 $(( ))
(( )) 的用法與let一樣怯疤,就不用多解釋了吧~~~
$(( ))就是把計(jì)算結(jié)果拿出來(lái)浆洗,可以用在雙引號(hào)里邊,比如:
echo "1+2=$(( 1 + 2 ))"
會(huì)輸出 1+2=3
( ):一個(gè)圓括號(hào)
在for循環(huán)里集峦,跟C語(yǔ)法一樣一樣的伏社。
或者是子程序,返回整個(gè)里邊表達(dá)的返回值塔淤。里邊的變量都是局部的摘昌,修改不會(huì)帶到外邊。舉例子
a=1
(a=3; echo $a)
echo a
結(jié)果是 3 1
還有個(gè)就是圈數(shù)組高蜂。聪黎。。這個(gè)就沒(méi)神馬意思了
[ ]:一個(gè)方括號(hào)备恤,是bash的命令稿饰,查man手冊(cè)是可以查到的,跟test一樣露泊,在手冊(cè)里可以看到很多用法喉镰。比如-b -c -gt -eq 什么的很多,還有用-a表示與滤淳,-o表示或等等
[[ ]]:一對(duì)方括號(hào)是一個(gè)方括號(hào)的加強(qiáng)版梧喷,則是Shell的保留字,里邊支持了 || && 等等這些符號(hào)脖咐。一般我喜歡用這個(gè)
還有相對(duì)復(fù)雜的 { }
幾個(gè)用處铺敌,區(qū)分變量,如:
var=abcd; echo ${var}EFG;
這樣屁擅,Bash就不會(huì)認(rèn)為變量是varEFG了
還有用來(lái)截取字符串的 ${ }語(yǔ)法比較靈活多變偿凭,這里不做多解釋?zhuān)蠹矣信d趣可以自己去搜搜資料,一般我腳本用到的字符串處理派歌,這個(gè)都能搞定了弯囊。
代碼塊痰哨。用來(lái)區(qū)分代碼的,但是跟( )有個(gè)區(qū)別匾嘱,就是在末尾要加上 ;
1.()
在子shell中運(yùn)行
(a=1);echo $a斤斧,結(jié)果是空,因?yàn)閍=1不是在當(dāng)前shell中運(yùn)行的(a=1);(echo $a)也是空的霎烙。不在同一個(gè)子shell中
數(shù)組的賦值撬讽,見(jiàn)最后的補(bǔ)充
2.(())
表達(dá)式計(jì)算
a=1;((a++)); echo $a,這時(shí)a就是2了悬垃。
3.<()和>()
進(jìn)程代入游昼,可以把命令的執(zhí)行結(jié)果當(dāng)成文件一樣讀入
比如comm前一般需要sort,那就可以這樣comm <(sort 1.lst) <(sort 2.lst)
或者是paste <(cut -t2 file1) <(cut -t1 file1)
尝蠕,和管道差不多烘豌,但是支持多個(gè)輸入。
4.$()
$(cmd) 執(zhí)行cmd的結(jié)果看彼,比如cmd是echo ls廊佩,那么就是執(zhí)行l(wèi)s,比如file$(which bash)靖榕,which bash的結(jié)果是/bin/bash罐寨,所以file $(which bash)等于file /bin/bash。如果你$(ls)序矩,而且你的當(dāng)前目錄下只有a b兩個(gè)文件鸯绿,那么就是執(zhí)行a b,然后系統(tǒng)會(huì)提示簸淀,命令沒(méi)找到瓶蝴。
5.$(())
表達(dá)式擴(kuò)展,和(())很相似租幕,但是這個(gè)是有點(diǎn)不同舷手,$(())不能直接$((b++)),b=1;echo $((++b))這時(shí)b等于2劲绪,顯示的也是2男窟,b=1;echo $((b++))這時(shí)b等于2,顯示的是1.
6.[]和[[]]
[]就是 test贾富,[]和[[]]都是條件表達(dá)式歉眷,不過(guò)[[]]有比[]高的容錯(cuò)性,如果a為空颤枪,那么[ $a -eq 0 ]會(huì)報(bào)錯(cuò)汗捡,但是[[ $a -eq 0 ]]不會(huì),所以一般都會(huì)使用[[]]或者是[ "$a" -eq 0 ]畏纲,[[]]支持的功能也比[]多扇住,比如[[ aaa =~a{3} ]]春缕,
[] 還有一種用途,如果你的當(dāng)前目錄下有a1-a9九個(gè)文件艘蹋,你可以用a[1-9]來(lái)替代這九個(gè)文件锄贼。有點(diǎn)需要注意,你不能用a[1-20]來(lái)代替a1- a20女阀,必須要a[1-9] a1[0-9] a20咱娶。
7.$[]
$(())的過(guò)去形式,現(xiàn)在已經(jīng)不建議使用
8.{}
{1..30} 就是1-30强品,或者是/{,s}bin/表示/bin/和/sbin/,ab{c,d,e}表示abc屈糊、abd的榛、abe
9.${}
變量,用法很多逻锐,可以查看man bash夫晌。
先寫(xiě)這些,以后想到再補(bǔ)充吧昧诱。
補(bǔ)充:()同時(shí)也是數(shù)組的賦值晓淀,比如a=(1 3 5),那么${a[0]}=1;${a[1]}=3;${a[2]}=5盏档,需要注意的是凶掰,下標(biāo)是從0開(kāi)始的
Shell中的括號(hào)有其特殊的用法, 現(xiàn)總結(jié)如下:
1. 符號(hào)$后的括號(hào)
${a} 變量a的值, 在不引起歧義的情況下可以省略大括號(hào).
$(cmd) 命令替換, 結(jié)果為shell命令cmd的輸出, 和`cmd`效果相同, 不過(guò)某些Shell版本不支持$()形式的命令替換, 如tcsh.
$((exp)) 和`expr exp`效果相同, 計(jì)算數(shù)學(xué)表達(dá)式exp的數(shù)值, 其中exp只要符合C語(yǔ)言的運(yùn)算規(guī)則即可, 甚至三目運(yùn)算符和邏輯表達(dá)式都可以計(jì)算.
2. 多條命令執(zhí)行
(cmd1;cmd2;cmd3) 新開(kāi)一個(gè)子shell順序執(zhí)行命令cmd1,cmd2,cmd3, 各命令之間用分號(hào)隔開(kāi), 最后一個(gè)命令后可以沒(méi)有分號(hào).
{ cmd1;cmd2;cmd3;} 在當(dāng)前shell順序執(zhí)行命令cmd1,cmd2,cmd3, 各命令之間用分號(hào)隔開(kāi), 最后一個(gè)命令后必須有分號(hào), 第一條命令和左括號(hào)之間必須用空格隔開(kāi).
對(duì){}和()而言, 括號(hào)中的重定向符只影響該條命令, 而括號(hào)外的重定向符影響到括號(hào)中的所有命令.
3. 雙括號(hào)的特殊用法
(()) 增強(qiáng)括號(hào)的用法, 常用于算術(shù)運(yùn)算比較. 雙括號(hào)中的變量可以不使用$符號(hào)前綴, 只要括號(hào)中的表達(dá)式符合C語(yǔ)言運(yùn)算規(guī)則, 支持多個(gè)表達(dá)式用逗號(hào)分開(kāi).
比如可以直接使用for((i=0;i<5;i++)), 如果不使用雙括號(hào), 則為for i in `seq 0 4`或者for i in {0..4}.
再如可以直接使用if (($i<5)), 如果不使用雙括號(hào), 則為if [ $i -lt 5 ].
[[]] 增強(qiáng)方括號(hào)用法, 常用于字符串的比較. 主要用于條件測(cè)試, 雙括號(hào)中的表達(dá)式可以使用&&, ||, <, >等C語(yǔ)言語(yǔ)法.
比如可以直接使用if [[ $a != 1 && $a != 2 ]], 如果不適用雙括號(hào), 則為if [ $a -ne 1] && [ $a != 2 ]或者if [ $a -ne 1 -a $a != 2 ].