Shell中变量和命令的各自替换方法,$,${},$(),批量修改文件名

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

posted @ 2019-07-08 14:00  柳思颐开心的一天  阅读(4325)  评论(0编辑  收藏  举报