如果对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