如果對shell命令做替換,可用 $(命令) 或反引號 `命令`:
1 #命令替換 2 [liusiyi@localhost ~]$ ls|grep t$ #直接顯示當前目錄下最后一個字符為t的文件名 3 arg.txt 4 char.txt 5 6 [liusiyi@localhost ~]$ echo $(ls|grep t$) #用變量形式,顯示當前目錄下最后一個字符為t的文件名 7 arg.txt char.txt 8 9 10 11 [liusiyi@localhost ~]$ echo `ls|grep t$` #用``等價於上面的$() 12 arg.txt char.txt 13 14 15 #下面這個例子,展示了$()比``的表達更優秀 16 [liusiyi@localhost ~]$ echo $(echo $(ls)) #echo里面嵌套了一個echo $(ls),易懂 17 about.sh aoooo..123.py arg.txt char.txt filemode1.smod.mod.mod file_rm_suffix.sh file_suffix.sh grep grepfolder hello laugh __mana meimei myfolder printargs.sh tempfolder touch 18 19 [liusiyi@localhost ~]$ echo `echo `ls`` #echo里面嵌套了一個echo `ls`,但結果不是我們需要的; 20 ls 21 [liusiyi@localhost ~]$ echo `echo \`ls\`` #里層的反引號需要轉義處理成 \` 才是我們需要的結果;這樣寫確實啰嗦了些,也容易出錯 22 about.sh aoooo..123.py arg.txt char.txt filemode1.smod.mod.mod file_rm_suffix.sh file_suffix.sh grep grepfolder hello laugh __mana meimei myfolder printargs.sh tempfolder touch 23 24 25 #所以結論是建議使用$()做命令替換,而非反引號``
做變量替換時,可以寫作$變量或 ${變量},具體區別是什么,看這個例子秒懂:
[liusiyi@localhost ~]$ name=Bob [liusiyi@localhost ~]$ echo $name is a boy Bob is a boy [liusiyi@localhost ~]$ echo ${name} is a boy Bob is a boy [liusiyi@localhost ~]$ echo $name_is_a_boy #$name后面如果跟 _,數字,字母等,系統會任務這是一個完整的變量,即#name_ [liusiyi@localhost ~]$ echo ${name}_is_a_boy #${name}可以很好的規避這類情況 Bob_is_a_boy [liusiyi@localhost ~]$ echo $name? #因為shell變量命名規則中是不能包括特殊符號的(比如?、*),所以這次$name?不會被當做一個完整變量 Bob? [liusiyi@localhost ~]$ echo ${name}? Bob?
批量修改某個目錄下的文件名,后面加上.mod;然后再把文件名復原,(附.sh腳本):
1 [liusiyi@localhost ~]$ ls #先看一下home下有哪些文件和文件夾 2 about.sh arg.txt filemode1.smod.mod.mod file_suffix.sh grepfolder laugh meimei printargs.sh touch 3 aoooo..123.py char.txt file_rm_suffix.sh grep hello __mana myfolder tempfolder 4 [liusiyi@localhost ~]$ file_suffix.sh ~ #運行腳本file_suffix.sh,為每一個文件名后面加.mod 5 this is a folder: /home/liusiyi/grep 6 this is a folder: /home/liusiyi/grepfolder 7 this is a folder: /home/liusiyi/myfolder 8 [liusiyi@localhost ~]$ ls #這時,home下的文件已經都被重命名了 9 about.sh.mod char.txt.mod file_suffix.sh.mod hello.mod meimei.mod tempfolder.mod 10 aoooo..123.py.mod filemode1.smod.mod.mod.mod grep laugh.mod myfolder touch.mod 11 arg.txt.mod file_rm_suffix.sh.mod grepfolder __mana.mod printargs.sh.mod 12 [liusiyi@localhost ~]$ file_rm_suffix.sh.mod ~ #把剛剛加上的.mod去掉;因為我本地本來就存了一份file_rm_suffix.sh,被前一個腳本改成了file_rm_suffix.sh.mod 13 this is a folder: /home/liusiyi/grep 14 this is a folder: /home/liusiyi/grepfolder 15 this is a folder: /home/liusiyi/myfolder 16 [liusiyi@localhost ~]$ ls #這時,home下的文件名都恢復了 17 about.sh arg.txt filemode1.smod.mod.mod file_suffix.sh grepfolder laugh meimei printargs.sh touch 18 aoooo..123.py char.txt file_rm_suffix.sh grep hello __mana myfolder tempfolder
[liusiyi@localhost ~]$ cat file_suffix.sh #查看腳本file_suffix.sh #!/bin/bash path=$1 for file in `ls $path` do if [ -d $path/$file ]; #如果$path/$file 存在且為一個目錄,則true then echo this is a folder: ${path}/${file} elif [ -f $path/$file ] ; #如果存在且為一個普通文件,則true then mv ${path}/${file} ${path}/${file}.mod else echo ${path}/${file} is unknow file type fi done #-------------------------------------------------------------------------#
[liusiyi@localhost ~]$ cat file_rm_suffix.sh #查看腳本file_rm_suffix.sh #!/bin/bash path=$1 for file in `ls $path` do if [ -d $path/$file ]; then echo this is a folder: $path/$file elif [ -f $path/$file ]; then mv ${path}/${file} $path/${file%%.mod} #這句${file%%.mod}是拿掉最後一個 .mod 及其右邊的字串,這里用到的一個方法${%%},下面還會詳細說 else echo ${path}/${file} is unknow file type fi done
如果想把一串命令都寫在一句,可以用 $(命令1;命令2) 或 ${ 命令1;命令2;},即用分號 ; 把命令串在一起,()和{}有一些區別:
1 [liusiyi@localhost ~]$ a=test 2 [liusiyi@localhost ~]$ echo $a 3 test 4 [liusiyi@localhost ~]$ (a=live;echo $a) #用$()把上面兩句合並在一起,唯一的區別是a=live,隔開命令用分號; 5 live 6 [liusiyi@localhost ~]$ echo $a #因為$()只是對一串命令重新開一個子shell進行執行,所以在當前shell看的話,$a的值還是test 7 test 8 [liusiyi@localhost ~]$ {a=live;echo $a} #現在嘗試用${}運行命令串,這個語法是錯誤的 9 -bash: {a=live: command not found 10 test} 11 [liusiyi@localhost ~]$ { a=live;echo $a;}#第一個大括號后面要留個空格且大括號里{}每個命令后面都要用分號; 12 live 13 [liusiyi@localhost ~]$ echo $a #用${}是對一串命令在當前shell執行,所以$a的值真的變成了live 14 live
${}還有一些奇葩(te shu)用法,${變量:-賦值內容},${變量:=賦值內容},${變量:+賦值內容},${變量:?賦值內容}給變量賦新的值,但是要遵從空或非空的原則,具體如下:
1 [liusiyi@localhost ~]$ echo $a #注意:變量a一開始沒賦值,即a值為空 2 3 [liusiyi@localhost ~]$ echo ${a:-newvalue} #用${變量:-字符串}這種形式給空值a賦值 4 newvalue 5 [liusiyi@localhost ~]$ echo $a #發現a還是一無所有 6 7 [liusiyi@localhost ~]$ unset a 8 [liusiyi@localhost ~]$ echo ${a:=newvalue} #用${變量:=字符串}這種形式給空值a賦值 9 newvalue 10 [liusiyi@localhost ~]$ echo $a #a終於有了值 11 newvalue 12 13 [liusiyi@localhost ~]$ unset a 14 [liusiyi@localhost ~]$ echo ${a:+newvalue} #再來看一下${變量:+字符串} 15 16 [liusiyi@localhost ~]$ echo $a #當a為空時,+這個方式是賦不了值的 17 18 [liusiyi@localhost ~]$ unset a 19 [liusiyi@localhost ~]$ echo ${a:?newvalue} #再引入一個${變量:?字符串},賦值給空a,它會把后面的字符串輸出到標准錯誤中,並從腳本中退出 20 -bash: a: newvalue 21 [liusiyi@localhost ~]$ echo $a #a一無所有 22 #以上一輪PK中,當變量a為空時,只有${變量:=字符串}才會真正給空值賦上值,其次是稍有一點點良心的?會打印出標准錯誤,而-和+都不會給空值賦值 23 24 25 26 [liusiyi@localhost ~]$ a=oldvalue #現在a=old value 27 [liusiyi@localhost ~]$ echo ${a:?newvalue} #a的值替換了${變量:?字符串},看輸出是oldvalue 28 oldvalue 29 [liusiyi@localhost ~]$ echo $a #a還是a 30 oldvalue 31 32 [liusiyi@localhost ~]$ a=oldvalue 33 [liusiyi@localhost ~]$ echo ${a:=newvalue} #當a不為空,=根本不改變什么,輸出還是oldvalue 34 oldvalue 35 [liusiyi@localhost ~]$ echo $a #a還是a,old! 36 oldvalue 37 38 [liusiyi@localhost ~]$ a=oldvalue 39 [liusiyi@localhost ~]$ echo ${a:-newvalue} #當a不為空,-和上面兩個表現一樣,輸出oldvalue 40 oldvalue 41 [liusiyi@localhost ~]$ echo $a #a還是old! 42 oldvalue 43 44 [liusiyi@localhost ~]$ a=oldvalue 45 [liusiyi@localhost ~]$ echo ${a:+newvalue} #字符串的值替換了${變量:+字符串},輸出是newvalue耶 46 newvalue 47 [liusiyi@localhost ~]$ echo $a #a還是a,old! 48 oldvalue 49 #這一輪PK中,當變量a不為空,只有${變量:+字符串}能給a重新賦上值,其他三組都是一樣,不改變a的值。
用表格來展示是這樣的——
命令 | 顯示的值 | 備注 | |
變量為空 | ${變量:-字符串} | 字符串 | |
變量 | 空 | ||
${變量:=字符串} | 字符串 | ||
變量 | 字符串 | 賦值默認值的常見做法 | |
${變量:+字符串} | 空 | ||
變量 | 空 | ||
${變量:?字符串} | 字符串被輸出到標准錯誤中,並從腳本中退出 | 可利用此特性來檢查是否設置了變量的值 | |
變量 | 空 | ||
變量非空 | ${變量:-字符串} | 變量 | |
變量 | 變量 | ||
${變量:=字符串} | 變量 | ||
變量 | 變量 | ||
${變量:+字符串} | 字符串 | ||
變量 | 字符串 | ||
${變量:?字符串} | 變量 | ||
變量 | 變量 |
還有${變量#匹配字符},${變量##匹配字符},${變量%匹配字符},${變量%%匹配字符} 這四種模式匹配替換,他們的最終結果都是要刪掉變量中的一部分內容。至於怎么刪,取決於中間的的#和% :
1 #變量賦值 2 [liusiyi@localhost ~]$ a=goooxxy_to_shool_xxyzkhk 3 4 #先看${變量#匹配字符},它實現的是:從前往后找到第一個匹配的字符,去掉前面(左邊)的內容——當然也包括去掉第一個匹配的字符 5 [liusiyi@localhost ~]$ echo ${a#*_} 6 to_shool_xxyzkhk 7 [liusiyi@localhost ~]$ echo ${a#_} #如果匹配字符串寫成 _, 而不是 *_,這樣是找不到的,因為從前往后找的話,變量值里的第一個字符根本不是 _,所以返回的還是一個完整的變量值 8 goooxxy_to_shool_xxyzkhk 9 [liusiyi@localhost ~]$ echo ${a#goo} #這樣是可以的,因為變量的前三個字符就是 goo,沒問題! 10 oxxy_to_shool_xxyzkhk 11 12 #看${變量##匹配字符},它實現的是:從前往后找到最后一個匹配的字符,去掉前面(左邊)的內容——當然也包括去掉最后一個匹配的字符 13 [liusiyi@localhost ~]$ echo ${a##*_} 14 xxyzkhk 15 16 #看${變量%匹配字符},它實現的是:從后往前找到第一個匹配的字符,去掉后面(右邊)的內容——當然也包括去掉第一個匹配的字符 17 [liusiyi@localhost ~]$ echo ${a%_*} 18 goooxxy_to_shool 19 20 #看${變量%%匹配字符},它實現的是:從后往前找到最后一個匹配的字符,去掉后面(右邊)的內容——當然也包括去掉第一個匹配的字符 21 [liusiyi@localhost ~]$ echo ${a%%_*} 22 goooxxy 23 24 #如果記不住#%對應的到底是從前往后還是從后往前,注意觀察鍵盤,# $ % 正好是【前/左】 【中】 【后/右】 25 #符號#就是從前往后順序的找匹配字符,找到后去掉前面的 26 #符號%就是從后往前倒敘的找匹配字符,找到后去掉后面的 27 #單個符號代表按順序的第一個 28 #雙符號代表按順序的最后一個 29 #用#的時候,如果要用到*,則*放在字符前面 30 #用%的時候,字符在*前面
再看一個中間帶冒號 : 的形式,${變量:字符起位置:字符末位置},它的作用是顯示指定位置的變量值內容:
1 [liusiyi@localhost ~]$ echo $a 2 goooxxy_to_shool_xxyzkhk 3 4 [liusiyi@localhost ~]$ echo ${a::10} #顯示前10個字符 5 goooxxy_to 6 7 [liusiyi@localhost ~]$ echo ${a:3:10} #顯示第3~第10的字符 8 oxxy_to_sh 9 10 [liusiyi@localhost ~]$ echo ${a:3:100}#顯示第3~第100的字符 11 oxxy_to_shool_xxyzkhk 12 13 [liusiyi@localhost ~]$ echo ${a:5:} #不能省去最后一個冒號后面的數字,否則什么也不輸出
用 ${變量/被替換的字符/替換字符} 來替換變量值里的字符:
1 [liusiyi@localhost ~]$ echo $a 2 goooxxy_to_shool_xxyzkhk 3 4 [liusiyi@localhost ~]$ echo ${a/ooo/sss} #用sss來替換變量值里的ooo 5 gsssxxy_to_shool_xxyzkhk 6 7 [liusiyi@localhost ~]$ echo ${a/o*/sss} #用sss來替換變量值里的o* 8 gsss 9 10 [liusiyi@localhost ~]$ echo ${a/_//} #用 斜杠/ 來替換變量值里的 下划線_ 11 goooxxy/to_shool_xxyzkhk 12 13 [liusiyi@localhost ~]$ echo $a #替換不改變變量的值 14 goooxxy_to_shool_xxyzkhk
用 ${#變量} 可統計變量值的個數:
1 #example1 2 [liusiyi@localhost ~]$ echo $a 3 goooxxy_to_shool_xxyzkhk 4 5 [liusiyi@localhost ~]$ echo ${#a} 6 24 7 8 #example2 9 [liusiyi@localhost ~]$ ls 10 a arg.txt file_rm_suffix.sh grepfolder __mana printargs.sh 11 about.sh char.txt file_suffix.sh hello meimei tempfolder 12 aoooo..123.py filemode1.smod.mod.mod grep laugh myfolder touch 13 14 [liusiyi@localhost ~]$ a=`ls` 15 16 [liusiyi@localhost ~]$ echo ${#a} 17 178
讀完這些不用的話,確實很容易忘記;但是如果讀別人的代碼時,見過這些規則,至少不會一頭霧水。
END