shell脚本【符号8】“$”:变量的引用/命令替换

这篇博客将会介绍符号“$”的功能:html

一、变量
      ① 变量分类(重点)      
shell

      ② 变量赋值             编程

            ① “=”并初始化            vim

            ② “=”不初始化           bash

            ③ read命令      
函数

      ③ 变量引用            spa

            ⑴ 变量引用的三种方式:             .net

            ⑵ 对于变量引用三种方式在使用上的区别说明:           
命令行

            ⑶ 举例 (里面的分析是重点             orm

                    ①首先看一个分号“;”例子:                   

                    ② 当变量的值中有特殊元字符时,加不加单引号或双引号的区别:                    

                    ③ 空格举例

    ④ 总结  (重点)
                  ⑴ 空格和分号之间区别
            ⑵ 变量引用后的不一样运用场景的区别

二、命令替换:$(command)         

 
 
 
 

1、变量 

    一、变量分类   (重点):

     根据用途能够分为四种变量:

            ①内部变量、②用户自定义变量、③环境变量、④参数变量 (变量的划分,每本书都不相同)

    ⑴  内部变量和环境变量共同点是:均为shell一启动就加载:点击打开连接

            环境变量是一组为系统内核、系统命令和应用程序提供运行环境而设定的变量的统称

            shell内部变量是特定为shell设定的一组变量的统称

                相同:都是同样用$引用,而且在脚本中都是一开始就有的,不须要用户再设定。

                不一样:环境变量能够添加、修改,用户能够从新定义:点击打开连接;可是shell内部变量是固定不变的。

    ⑵  用户自定义变量:用户本身设置的变量  (参考《Linux Shell编程从入门到精通》-张昊著)

        用户自定义变量,又可分为:局部变量和全局变量。

        局部变量:只在代码块或函数有效,出了代码块或函数,就消失的变量;在代码块或函数中声明的局部变量,必须经过local声明,不然它也是对当前shell进程均可见的。

        全局变量:在当前shell进程中,都可见的变量。无需额外加声明,它既是当前shell进程的一个全局变量。

        全局变量能够升级成为临时环境变量,经过export进行声明,使当前进程的子进程也能使用这一变量。

        同时,你会发现这个临时环境变量和⑴中的环境变量有点不一样。他们均叫环境变量是由于:他们都是为当前执行的进程提供运行环境的变量;不一样在于,临时环境变量只对该运行环境有效,若是你执行另一个shell脚本,这个临时环境变量无能为力:点击打开连接

    ⑶ 位置参数就是传参的数据。位置参数是传给函数,语句块等等的数据,能够经过$1 $2…$N等配合shell内部变量,如$?  $@等进行引用

    二、变量赋值

    变量的赋值,三种方式:

        ① “=”并初始化

        好比:var=value  (注意:若是value是带有空格的字符串,须要加单或双引号)

        举例:c=he llo

        输出:No command ‘llo’ found

        分析:在读完命令以后,会对字符串或关键字按照空格切割,切割以后,分为了两个部分:c=he和llo。c=he被理解为一个变量赋值,而llo却找不到匹配的项,而且检索不到相关的命令,因此就会输出这个llo的报错。

            若是赋的值是由多个单词组成的字符串,应该在字符串先后增长单、双引号。

        ② “=”不初始化

        好比:var=         (未赋值变量,值为null)

        ③ read命令

            read命令是读取标准输入的数据,而后存储到指定的变量中。这里须要注意:read接收的是标准输入而不是参数,read命令是不接收参数的。

        脚本举例:test.sh

            代码:

                    if [[ chj = name ]]

                    then

                            echo chen

                    else

                            read a

                            echo $a

                    fi

        执行命令:bash test.sh

        执行完后,会让你从标准输入进行输入,并把值赋给变量a.

        若是执行命令:bash test.sh name

        这一句命令本意是把name做为参数传给变量a,这种方式是不可能的。由于read命令不接收参数。

    三、变量引用:

    ⑴ 变量引用的三种方式:

         ① $variable

         ② ${variable}

         ③“$variable”“${variable}”

     分析:其实第3种就是第一、2种状况加一个双引号,可是在运用场景上会有必定的差异。特别是在一些以空格为分割的场景和一些带有特殊字符的场景下。

       同时至于第3种状况会发现,在变量引用两边加了双引号,可是里面的变量正常引用,这里能够看一下双引号的使用:点击打开连接

    ⑵ 对于变量引用三种方式在使用上的区别说明:

         首先讲解一下,为何这三种在使用上会有区别:

         答:其实就是由于双引号的关系。引用变量后,双引号会对于引用结果中空格和一些特殊符号进行的解析或者不解析。而引用结果用的空格在命令中的分隔做用会彻底改变一个命令的输出,而特殊符号的是否解析也会影响最终的输出结果。

    ⑶ 举例   (重点)

    ①首先看一个分号“;”例子:

        脚本例子:test

        代码:

            a=”chen;haojie”   #双引号扩起来的字符中间是一个分号“;”

            echo $a

     输出:chen;haojie

       进行对比的例子:

            a=chen;haojie

     输出:haojie: command not found

     分析:命令读取时,遇到分号“;”,这个命令的读取就结束了,因此,前面读取到的是命令a=chen,并执行它。后面一部分:haojie,会被当作另外一个命令来处理,因为没有相关的命令因此报错。

    ② 当变量的值中有特殊元字符时,加不加单引号或双引号的区别:

     脚本举例:test1.sh

                        c=he*

                        echo $c

     输出是:当前目录下的全部以he为开头的文件

     对比脚本举例:test2.sh(对比test1.sh)

                         c=he*

                         echo “$c”

     输出是:he*。

        解析:符号“*”在双引号中不解释。那什么状况下,会解释呢?

        以test2.sh为原型,再看一个对比例子

        好比第一句改成,c="$(ls -l)" 或 c=$(ls -l),第二句维持不变,echo "$c"。

        其实这两种是同样的。不过你要弄清的是,c="$(ls -l)"和c=$(ls -l),在分别执行到这一句时,命令ls -l就已经执行了,赋给变量c的是命令执行的结果,而不是在语句echo "$c"这里才进行的替换。因此这里你须要弄清楚,当前该句的命令是怎样执行的。

        注意:这里抛出的是另外一个问题:变量引用形式,在不一样场景下的使用区别。

                  ⒈若是是用变量引用或命令替换的形式(  $(ls -l)  ),为变量c进行的“=”赋值操做。那么这个变量引用或命令替换的输出结果中,空格或换行符是天然地做为整个字符串的一部分,而不是分隔符,此时就无关有无单、双引号。

                  ⒉可是,若是变量引用或命令替换的形式,做为命令或函数或语句块的参数,这个变量引用或命令替换输出结果中的空格或换行符,在不加单、双引号的状况下就是做为分隔符。此时,有无单、双引号直接关系到读取到的参数及参数个数。

        简单点说:变量引用或命令替换后,在运用到不一样的场景,好比“=”赋值和做为参数两种不一样状况时,其输出结果中的空格在处理时是有区别的,此时单、双引号的做用就很是关键。

        那么,在引用变量进行变量赋值时,如何取被引用变量中的某些字符,而不是所有呢:点击打开连接,甚至能够用${var:pos:len},配合while [[ ${var:pos:len} = MouChar ]] ;do let pos+=1或let len+=1 done的情势,来截取中间你想要的字符串。

        因此,单引号、双引号在变量引用中,对于其结果中的某些特殊字符的使用有必定的影响。

     ③ 空格举例

      脚本举例:test1.sh和test2.sh

         test1.sh代码(为了便于分析,在命令前加了标号,vim中:set nu):

                    1 name2=”d s”;

                    2 a=$name2

                    3 echo $a

                    4 bash test2.sh “$name2”

                    5 bash test2.sh $name2

          test2.sh代码:

                    echo $1

                    echo $2

          输出:

                    d s                  #第三句的输出

                    d s                  #第四句的输出

            【这是一个空行】     #第四句的输出    

                    d                    #第五句的输出

                    s                    #第五句的输出

     分析:代码其实能够分为两个部分:test1.sh脚本中的123句是用来和45进行对比的。即123一个部分,145是一个部分。

     第三句输出了d s,说明a的赋值过程,是完整赋值,而不是相似于a=d s这种赋值。详细解释可看第②个例子。

        第四句和第五句是用来对比的,用来讲明空格在参数分隔中的做用。

   四、总结   (重点)

     空格和分号之间区别(从上述脚本例子①②③得出的总结):

        从例子③能够看出:空格键(Space)做用是变量、关键字等之间分隔。另一个一样做为字符串和关键字之间分隔的符号还有:制表符(Tab)。

       从例子①能够看出:分号“;”是用于一个命令读入的结束标志。另外,做为命令行结束标志的符号还有:后台进程“&”、逻辑与“&&”、逻辑或“||”、换行符“Enter”。

        做为分隔,和做为结束,这两个之间的区别:

             做为分隔的符号:空格和制表符。做用于,命令与参数之间的分隔、参数与参数之间的分隔等等。简言之,就是命令不一样部分之间的分隔。

           做为命令行读入的结束标志:分号、后台进程符号&、逻辑与&&、逻辑或||、换行符。用于表示这是一个完整的命令行。在命令解析过程当中,先是读取完整的命令行,待完整的命令行被读取后,才是按照空格或制表符来分割各个部分。

            以下命令:

                bash test2 1 2;echo a

       执行过程是,先读取一个命令行:bash test2 1 2,以分号做为命令行结束标志。读取命令行结束后,对命令行中的字符、变量、关键字(如命令等)按照空格或换行符来进行分割,以后才是进行其它操做。具体能够查看:命令行解释执行过程。前一个命令行执行完以后,再是对echo a命令行的读取,命令行结束标志符是:换行符。

        ⑵ 变量引用后的不一样运用场景的区别

        变量引用后,若是是做为“=”赋值状况,则引用结果中的空格做为整个字符串的一部分,无关是否加双引号;若是是做为命令、函数等参数,则引用结果中的空格会成为分隔符,此时加不加双引号对结果影响很大。

        同时,对于引用变量中的某些某些字符,能够经过截断的方式,或者是${var:pos:len}来进行截取变量中的某些字符:点击打开连接

2、命令替换:$(command)

        命令替换的目的是获取命令的输出、为变量赋值,或对命令的输出作进一步的处理。

        命令替换的实现:$(…) (虽然也能够用反引号替换)

        同时注意:双引号中$符号是解释的:点击打开连接