zoukankan      html  css  js  c++  java
  • 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 

  • 相关阅读:
    算法与数据结构基础
    算法与数据结构基础
    算法与数据结构基础
    算法与数据结构基础
    算法与数据结构基础
    算法与数据结构基础
    最佳实践 根据状态操作,这样能避免吃掉异常
    最佳实践 状态设计
    Android HTTPS如何10分钟实现自签名SSL证书
    马桶选购
  • 原文地址:https://www.cnblogs.com/happyliusiyi/p/11150786.html
Copyright © 2011-2022 走看看