来自 电脑知识 2019-09-13 23:08 的文章
当前位置: 威尼斯国际官方网站 > 电脑知识 > 正文

【威尼斯国际官方网站】Shell编程

Shell历史

  • Shell的坚守是解释客户的授命,客商输入一条命令,Shell就分解进行一条,那条措施叫做交互式(interactive),Shell还大概有一种实施命令的章程叫做批管理(batch),客户优先写二个Shell脚本(script),个中有成都百货上千条命令,让Shell贰回把这个命令实践完,而不必一条条地敲命令。Shell脚本和编程语言相似,也许有变量和流程序调整制语句,但Shell脚本是演说实践的,无需编写翻译,Shell程序从剧本中一行一行读取并实施这一个命令,约等于三个客户把脚本中的命令一行一行敲到Shell提醒符下施行。
  • 鉴于历史原因,UNIX系统上有很种种Shell:

    • 1、sh(Bourne Shell):由SteveBourne开采,各个UNIX系统都配有sh。
    • 2、csh(C Shell):由Bill Joy开采,随BSD UNIX公布,它的流水生产线调控语句很象C语言,帮衬广大Bourne Shell把不帮衬的作用:作业调控,命令历史,命令行编辑。
    • 3、ksh(Korn Shell):由DavidKorn开拓,向后十一分sh的效果,况兼增添了csh引进的新职能,是日前数不清UNIX系统标准配置的Shell,在那几个种类上/bin/sh往往是指向/bin/ksh的记号链接。
    • 4、tcsh(TENEX C Shell):是csh的提升版本,引进了指令补全等功用,在FreeBSD、MacOS X等体系上代表了csh。
    • 5、bash(Bourne Again Shell):由GNU开辟的Shell,重要目的是与POSIX标准保持一致,同时兼任对sh的优良,bash从csh和ksh借鉴了众多效果与利益,是各类Linux发行版规范配置的Shell,在Linux系统上/bin/sh往往是指向/bin/bash和标识链接。尽管这么,bash和sh照旧有比非常多不一的,一方面,bash扩展了一些限令和参数,另一方面,bash并不完全和sh包容,有个别行为并区别,所以bash供给效法sh的一颦一笑:当大家透过sh那一个程序名运行bash时,bash能够伪装自身是sh,不认扩张的命令,何况作为与sh保持一致。

        $ cat /etc/passwd
        root:x:0:0:root:/root:/bin/zsh
        daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
        bin:x:2:2:bin:/bin:/usr/sbin/nologin
        sys:x:3:3:sys:/dev:/usr/sbin/nologin
        sync:x:4:65534:sync:/bin:/bin/sync
      
  • 客商在命令行输入指令后,一般景况下Shell会fork并exec该命令,可是Shell的内建命令例外,试行内建命令约等于调用Shell进程中的三个函数,并不创立新的进度。从前学过的cd、alias、umask、exit等一声令下就是内建命令,凡是用which命令查不到程序文件所在地方的下令都是内建命令,内建命令未有独立的man手册,要在man手册中查看内建命令,应该进行

      $ man bash-builtins
    
  • 如export、shift、if、eval、[、for、while等等。内建命令纵然不创设新的进度,但也可能有Exit Status,平时也用0表示成功非零代表战败,就算内建命令不创设新的长河,但实行完成后也可以有三个状态码,也得以用极度变量$?读出。

Shell编程,linuxshell编程

推行脚本

  • 编辑三个粗略的脚本test.sh:

      #! /bin/sh
      cd ..
      ls
    
  • Shell脚本中用#代表注释,相当于C语言的//注释。但假若#放在第一行早先,而且是#!(称为Shebang)则分裂,它代表该脚本使用后边内定的演讲器/bin/sh解释施行。如若把那几个本子文件加上可进行权限然后实施:

      $ chmod a+x test.sh
      $ ./test.sh
    
  • Shell会fork七个子历程并调用exec试行./test.sh其一顺序,exec系统调用应该把子进程的代码段替换成./test.sh次第的代码段,并从它的_start始发施行。可是test.sh是个文件文件,根本未曾代码段和_start函数,怎么做吧?其实exec还会有其它一种体制,假若要实行的是二个文件文件,而且第一行用Shebang钦命理解释器,则用解释程序的代码段替换当前经过,并且从解释器的_start早先实施,而以此文件文件被当作命令行参数传给解释器。因而,试行上述脚本也就是实践顺序

      $ /bin/sh ./test.sh
    
  • 以这种方法实施不须求test.sh文件可推行权限。

  • 假定将指令行下输入的一声令下用()括号括起来,那么也会fork出三个子Shell推行小括号中的命令,一行中得以输入由支行;隔开分离的多个命令,比方:

      $ (cd ..; ls -l)
    
  • 和地点两种办法施行Shell脚本的作用是同等的,cd ..一声令下改动的是子Shell的PWD,而不影响到交互式Shell。

      $ cd ..; ls -l
    
  • 则不相同的效益,cd ..一声令下是一向在交互式Shell下举办的,改动交互式Shell的PWD,但是这种办法约等于如此举办Shell脚本:

      $ source ./test.sh
      或者
      $ . ./test.sh
    
  • source大概.命令是Shell的内建命令,这种办法也不会创立子Shell,而是直接在交互式Shell下逐行实施脚本中的命令。

Shell历史

  • Shell的意义是演说顾客的指令,客商输入一条命令,Shell就分解推行一条,这条办法叫做交互式(interactive),Shell还应该有一种实施命令的章程叫做批管理(batch),客商优先写三个Shell脚本(script),当中有数不尽条命令,让Shell壹回把这几个命令实行完,而不必一条条地敲命令。Shell脚本和编制程序语言相似,也会有变量和流程序调整制语句,但Shell脚本是分解奉行的,无需编写翻译,Shell程序从剧本中一行一行读取并实行那个命令,也正是三个顾客把脚本中的命令一行一行敲到Shell提醒符下实施。
  • 出于历史原因,UNIX系统上有很二种Shell:

    • 1、sh(Bourne Shell):由SteveBourne开辟,各个UNIX系统都配有sh。
    • 2、csh(C Shell):由Bill Joy开辟,随BSD UNIX公布,它的流水生产线调控语句很象C语言,协理广大Bourne Shell把不支持的遵从:作业调控,命令历史,命令行编辑。
    • 3、ksh(Korn Shell):由DavidKorn开荒,向后十分sh的意义,何况加多了csh引进的新成效,是现阶段数不尽UNIX系统标准配置的Shell,在这么些种类上/bin/sh往往是指向/bin/ksh的标记链接。
    • 4、tcsh(TENEX C Shell):是csh的增加版本,引进了指令补全等职能,在FreeBSD、MacOS X等系统上代表了csh。
    • 5、bash(Bourne Again Shell):由GNU开拓的Shell,首要指标是与POSIX规范保持一致,同有时间专职对sh的相称,bash从csh和ksh借鉴了成都百货上千效应,是种种Linux发行版标准配置的Shell,在Linux系统上/bin/sh往往是指向/bin/bash和符号链接。尽管那样,bash和sh照旧有广大见仁见智的,一方面,bash扩充了一部分发令和参数,另一方面,bash并不完全和sh包容,有些行为并不等同,所以bash须要效法sh的作为:当大家透过sh那么些程序名运行bash时,bash能够假装本人是sh,不认扩充的授命,况且作为与sh保持一致。

      $ cat /etc/passwd
      root:x:0:0:root:/root:/bin/zsh
      daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
      bin:x:2:2:bin:/bin:/usr/sbin/nologin
      sys:x:3:3:sys:/dev:/usr/sbin/nologin
      sync:x:4:65534:sync:/bin:/bin/sync
      
  • 客户在命令行输入指令后,一般情形下Shell会fork并exec该命令,不过Shell的内建命令例外,实施内建命令约等于调用Shell进度中的七个函数,并不创建新的长河。以前学过的cd、alias、umask、exit等一声令下正是内建命令,凡是用which命令查不到程序文件所在地方的通令都是内建命令,内建命令未有独立的man手册,要在man手册中查看内建命令,应该施行

    $ man bash-builtins
    
  • 如export、shift、if、eval、[、for、while等等。内建命令尽管不创制新的进度,但也可能有Exit Status,日常也用0表示成功非零象征失败,尽管内建命令不创制新的历程,但推行完结后也可能有叁个状态码,也能够用非常变量$?读出。

基本语法

实行脚本

  • 编辑二个轻松的脚本test.sh:

    #! /bin/sh
    cd ..
    ls
    
  • Shell脚本中用#代表注释,约等于C语言的//注释。但即使#坐落第一行开始,何况是#!(称为Shebang)则分裂,它意味着该脚本使用前面钦赐的分解器/bin/sh解释施行。假设把那么些本子文件加上可奉行权限然后试行:

    $ chmod a+x test.sh
    $ ./test.sh
    
  • Shell会fork贰个子进度并调用exec推行./test.sh以此顺序,exec系统调用应该把子进度的代码段替换到./test.sh次第的代码段,并从它的_start初叶推行。可是test.sh是个文件文件,根本未曾代码段和_start函数,如何是好呢?其实exec还应该有别的一种机制,假若要进行的是一个文件文件,何况第一行用Shebang钦点明白释器,则用解释程序的代码段替换当前进度,并且从解释器的_start始于实践,而那一个文件文件被当作命令行参数字传送给解释器。由此,实施上述脚本相当于推行顺序

    $ /bin/sh ./test.sh
    
  • 以这种方法进行无需test.sh文件可实行权限。

  • 即使将下令行下输入的通令用()括号括起来,那么也会fork出多少个子Shell试行小括号中的命令,一行中能够输入由支行;隔开分离的八个命令,比方:

    $ (cd ..; ls -l)
    
  • 和地方三种格局实施Shell脚本的效应是同样的,cd ..命令改换的是子Shell的PWD,而不影响到交互式Shell。

    $ cd ..; ls -l
    
  • 则分化的效能,cd ..一声令下是间接在交互式Shell下实行的,改动交互式Shell的PWD,但是这种办法相当于那般实行Shell脚本:

    $ source ./test.sh
    或者
    $ . ./test.sh
    
  • source恐怕.命令是Shell的内建命令,这种办法也不会创建子Shell,而是直接在交互式Shell下逐行施行脚本中的命令。

变量

  • 依据规矩,Shell变量经常由字母加下划线起初,由跋扈长度的字母、数字、下划线组成。有三种档案的次序的Shell变量:
    • 1、情形变量
      • 景况变量能够从父进度传给子进度,因些Shell进度的情状变量能够从眼下Shell进度传给fork出来的子进度。用printenv指令能够来妥当前Shell的意况变量。
    • 2、本地变量
      • 只存在于如今Shell进度,用set一声令下能够显稳当前Shell进度中定义的具有变量(包罗当地变量和蒙受变量)和函数。
  • 景况变量是任何进度都有的概念,而本地变量是Shell特有的定义。在Shell中,情况变量和本土变量的概念和用法相似。在Shell中定义或赋值贰个变量:

      $ VARNAME=value
    
  • 瞩目等号两侧都不能够有空格,否则会被Shell解释成命令行参数。

  • 多少个变量定义后仅存在于前段时间Shell进度,它是本土变量,用export命令能够把地面变量导出为意况变量,定义和导出情状变量平时可以一步成功:

      $ export VARNAME=value
    
  • 也能够分两步成功:

      $ VARNAME=value
      $ export VARNAME
    
  • 用unset命令能够删除已定义的意况变量或地面变量。

      $ unset VARNAME
    
  • 尽管一个变量叫做VAKoleosNAME,用'VAPAJERONAME'能够表示它的值,在不引起歧义的情事下也得以用VAPAJERONAME表示它的值。通过以下的例证相比较那三种表示法的不及:

      $ echo $SHELL
    
  • 只顾,在概念变量时毫无"'",取变量值时要用。和C语言区别的是,Shell变量无需明显定义类型,事实上Shell变量的值都以字符串,比方大家定义VA奥德赛=45,其实VA揽胜的值是字符串45而非整数。Shell变量不必要先定义后选取,即使三个尚无概念的变量取值,则值为空字符串。

基本语法

文本名代换(Globbing)

  • 那个用于匹配的字符称为通配符(魏尔德card),如:*?[],具体如下:

    • *相配0个或多个随机字符
    • ?协作四个随意字符
    • [若干字符]合作方括号中随机一个字符的一回出现

        $ ls /dev/ttyS*
        $ ls ch0?.doc
        $ ls ch0[0-2].doc
        $ ls ch[012][0-9].doc
      
    • 小心,Globbing所匹配的文件名是由Shell张开的,也正是说在参数还没传给程序在此之前曾经开展了,例如上述ls ch0[012].doc一声令下,借使当前目录下有ch00.doc和ch02.doc,则传给ls命令的参数实际上是那七个文件名,并非贰个相称字符串。

变量

  • 根据常规,Shell变量平常由字母加下划线起始,由随机长度的字母、数字、下划线组成。有两种档期的顺序的Shell变量:

    • 1、景况变量
      • 景况变量能够从父进程传给子进度,因些Shell进度的意况变量能够从眼下Shell进度传给fork出来的子进度。用printenv命令能够显妥贴前Shell的情况变量。
    • 2、本地变量
      • 只存在于近来Shell进程,用set命令能够显伏贴前Shell进度中定义的装有变量(满含地点变量和景况变量)和函数。
  • 境况变量是任何进程皆某个概念,而本地变量是Shell特有的概念。在Shell中,蒙受变量和本土变量的定义和用法相似。在Shell中定义或赋值四个变量:

    $ VARNAME=value
    
  • 注意等号两侧都不能有空格,不然会被Shell解释成命令行参数。

  • 二个变量定义后仅设有于近期Shell进度,它是本土变量,用export命令能够把地面变量导出为碰到变量,定义和导出情形变量平常能够一步成功:

    $ export VARNAME=value
    
  • 也得以分两步成功:

    $ VARNAME=value
    $ export VARNAME
    
  • 用unset命令能够删除已定义的遭逢变量或地面变量。

    $ unset VARNAME
    
  • 假如二个变量叫做VA奥德赛NAME,用'VA宝马X3NAME'可以表示它的值,在不引起歧义的事态下也得以用VASportageNAME表示它的值。通过以下的例证相比这三种表示法的不如:

    $ echo $SHELL
    
  • 小心,在概念变量时不要"'",取变量值时要用。和C语言区别的是,Shell变量没有需求通晓概念类型,事实上Shell变量的值都以字符串,举例大家定义VAPRADO=45,其实VA景逸SUV的值是字符串45而非整数。Shell变量没有须要先定义后使用,假设二个一向不概念的变量取值,则值为空字符串。

一声令下代换

  • 由“`”反引号括起来的也是一条命令,Shell先进行该命令,然后将出口结果立时期换成当前下令行中。比如定义三个变量存放date命令的出口:

      $ DATE=`date`
      $ echo $DATE
    
  • 一声令下代换也足以用$()表示:

      $ DATE=$(date)
    

文件名代换(Globbing)

  • 这么些用于般配的字符称为通配符(Wildcard),如:*?[],具体如下:

    • *相配0个或多个随机字符
    • ?非常二个专断字符
    • [多少字符]杰出方括号中自由四个字符的三回面世

      $ ls /dev/ttyS*
      $ ls ch0?.doc
      $ ls ch0[0-2].doc
      $ ls ch[012][0-9].doc
      
    • 注意,Globbing所相配的文书名是由Shell展开的,也正是说在参数还没传给程序在此以前早就进展了,比方上述ls ch0[012].doc命令,假诺当前目录下有ch00.doc和ch02.doc,则传给ls命令的参数实际上是那四个文本名,并不是二个相称字符串。

算术代换

  • 运用$(()),用于算术总计,(())中的Shell变量取值将转变来整数,同样含义的$[]等价,例如:

      $ VAR=45
      $ echo $(($VAR+3))   等价于 echo $[VAR+3]或$[$VAR+3]
    
  • $(())中不得不用+-*/和()运算符,况且不得不做整数运算。

  • $[base#n],个中base表示进制,n依照base进制解释,前边再运算数,按十进制解释。

      $ echo $[2#10+11]
      $ echo $[8#10+11]
      $ echo $[16#10+11]
    

指令代换

  • 由“`”反引号括起来的也是一条命令,Shell先实践该命令,然后将出口结果即时期换成当前下令行中。比方定义多少个变量存放date命令的出口:

    $ DATE=`date`
    $ echo $DATE
    
  • 指令代换也得以用$()表示:

    $ DATE=$(date)
    

转义字符

  • 和C语言类似,在Shell中被当做转义字符,用于去除紧跟其后的单个字符的奇异意义(回车除此而外),换句话说,紧跟其后的字符取字面值。比方:

      $ echo $SHELL
      /bin/bash
      $ echo $SHELL
      $SHELL
      $ echo \
      
    
  • 比如说创立二个文书名称叫"$ $"的公文($间含有空格),能够那样:

      $ touch $ $
    
  • 再有一个字符就算不富有非凡意义,然而要用它做文件名也很艰难,便是-号。假使要创立多个文件名以-号起初的文本,那样是不得法的:

      $ touch -hello
      touch:无效选项 -- e
      Try 'touch --help' for more information.
    
  • 即便加上转义也还是报错:

      $ touch -hello
      touch:无效选项 -- e
      Try 'touch --help' for more information.
    
  • 因为各样UNIX命令都把-号开关的命令行参数作为命令的选项,而不会作为文件名。,假若非要管理以-号早先的文书名,也可以有三种办法:

      $ touch ./-hello
      或者
      $ touch -- -hello
    

算术代换

  • 动用$(()),用于算术总计,(())中的Shell变量取值将转产生整数,同样含义的$[]等价,例如:

    $ VAR=45
    $ echo $(($VAR+3))   等价于 echo $[VAR+3]或$[$VAR+3]
    
  • $(())中只可以用+-*/和()运算符,並且不得不做整数运算。

  • $[base#n],当中base表示进制,n依照base进制解释,后边再运算数,按十进制解释。

    $ echo $[2#10+11]
    $ echo $[8#10+11]
    $ echo $[16#10+11]
    

单引号

  • 和C语言同,Shell脚本中的单引号和双引号同样是字符串的界定符(双引号下一节介绍),并不是字符的界定符。单引号用于保险引号内部存款和储蓄器有字符的字面值,即便引号内的和回车也不例外,然而字符串中不可能出现单引号。假设引号没有配成对就输入回车,Shell会给出续行提醒符,供给客商把引号配上对。比方:

      $ echo '$SHELL'
      $SHELL
      $ echo 'ABC(回车)
      > DE'(再按一次回车结束命令)
      ABC
      DE
    

转义字符

  • 和C语言类似,在Shell中被看做转义字符,用于去除紧跟其后的单个字符的自我作古意义(回车除此之外),换句话说,紧跟其后的字符取字面值。比方:

    $ echo $SHELL
    /bin/bash
    $ echo $SHELL
    $SHELL
    $ echo \
    
    
  • 比如说创立二个文件名称叫"$ $"的文件($间含有空格),能够这么:

    $ touch $ $
    
  • 再有一个字符固然不具有非常意义,可是要用它做文件名也很麻烦,就是-号。假使要创立一个文书名以-号开首的文件,那样是不科学的:

    $ touch -hello
    touch:无效选项 -- e
    Try 'touch --help' for more information.
    
  • 正是加上转义也还是报错:

    $ touch -hello
    touch:无效选项 -- e
    Try 'touch --help' for more information.
    
  • 因为种种UNIX命令都把-号按键的命令行参数作为命令的选项,而不会作为文件名。,如若非要管理以-号起先的文本名,或许有三种情势:

    $ touch ./-hello
    或者
    $ touch -- -hello
    

双引号

  • 被双引号用括住的开始和结果,将被视为单一的字串。它幸免通配符扩大,但允许变量扩大。那一点与单引号的管理方式分化

      $ DATE=$(date)
      $ echo "$DATE"
      $ echo '$DATE'
    
  • 再比如:

      $ VAR=200
      $ echo $VAR
      200
      $ echo '$VAR'
      $VAR
      $ echo "$VAR"
      200
    

单引号

  • 和C语言同,Shell脚本中的单引号和双引号一样是字符串的界定符(双引号下一节介绍),并非字符的界定符。单引号用于保证引号内具有字符的字面值,即便引号内的和回车也不例外,可是字符串中不可能出现单引号。若是引号未有配成对就输入回车,Shell会给出续行提示符,需要顾客把引号配上对。举个例子:

    $ echo '$SHELL'
    $SHELL
    $ echo 'ABC(回车)
    > DE'(再按一次回车结束命令)
    ABC
    DE
    

Shell脚本语法

双引号

  • 被双引号用括住的开始和结果,将被视为单一的字串。它防止通配符扩充,但允许变量扩张。那点与单引号的管理格局不一致

    $ DATE=$(date)
    $ echo "$DATE"
    $ echo '$DATE'
    
  • 再比如:

    $ VAR=200
    $ echo $VAR
    200
    $ echo '$VAR'
    $VAR
    $ echo "$VAR"
    200
    

条件测量试验

  • 命令test或[能够测验贰个条件是还是不是创建,就算测验结果为真,则该命令的Exit Status为0,假设测验结果为假,则下令的Exit Status为1(注意与C语言的逻辑表示正好相反)。举例测验三个数的高低关系:

      $ var=2
      $ test $var -gt 1
      $ echo $?
      0
      $ test $var -gt 3
      $ echo $?
      1
    
  • 即便如此看起来很想获得,但左手括号[确实是叁个下令的名字,传给命令的各参数之间应该用空格隔离,比如:$VA帕杰罗、-gt、3、]和[指令的八个参数,它们中间必得用空格隔开分离。命令test或[的参数情势是均等的,只不过test命令无需]参数。以[一声令下为例,常见的测量检验命令如下表所示:

      [ -d DIR ]                 如果DIR存在并且是一个目录则为真
      [ -f FILE ]                如果FILE存在且是一个普通文件则为真
      [ -z STRING ]              如果STRING的长度为零则为真
      [ -n STRING ]              如果STRING的长度非零则为真
      [ STRING1 = STRING2 ]      如果两个字符串相同则为真
      [ STRING1 != STRING2 ]     如果两个字符串不相同则为真
      [ ARG1 OP ARG2 ]           ARG1和ARG2应该是整数或者取值为整数的变量,
                                 OP的值有:
                                      -eq     等于
                                      -ne     不等于
                                      -lt     小于
                                      -le     小于等于
                                      -gt     大于
                                      -ge     大于等于
    
  • 和C语言类似,测量试验条件之间还可以做与、或、非逻辑运算:

      [ ! EXPR ]           EXPR可以是上表中的任意一种测试条件, !表示"逻辑反(非)"
      [EXPR1 -a EXPR2 ]    EXPR1和EXPR2可以是上表中的任意一种测试条件,-a表示“逻辑与”
      [EXPR1 -o EXPR2 ]    EXPR1和EXPR2可以是上表中的任意一种测试条件,-o表示“逻辑或”
    
  • 例如:

      $ VAR=abc
      $ [ -d Desktop -a $VAR = 'abc' ]
      $ echo $?
      0
    
  • 瞩目,假设上例中的$VA奔驰G级变量事先未有定义,则被Shell张开为空字符串,会产生测量试验条件的语法错误(张开为[ -d Desktop -a = 'abc']),作为一种好的Shell编制程序习于旧贯,应该总是把变量取值放在双引号之中(展开为[ -d Desktop -a "" = 'abc'])

      $ unset VAR
      $ [ -d Desktop -a $VAR = 'abc' ]
      -bash: [: 参数太多
      $ [ -d Desktop -a "$VAR" = 'abc' ]
      $ echo $?
      1
    

Shell脚本语法

分支

  • if/then/elif/else/fi

    • 和C语言类似,在Shell中用if、then、elif、else、fi这几条命令完成分支调节。这种流程序调节制语句本质上也是由若干条Shell命令组成的,举个例子在此以前讲过的

        if [ -f ~/.bashrc ]; then
            . ~/.bashrc
        fi
      
    • 事实上是三条命令,if [ -f ~/.bashrc ]是第一条,then . ~/.bashrc是第二条,fi是第三条。假若两条命令写在同一行则必要用;号隔绝,一行只写一条命令就无需写;号了,别的,then前面有换行,但那条命令没写完,Shell会自动续行,把下一行接在then后边当作一条命令管理。和[命令同样,要专心命令和各参数之间必需用空格隔开。if命令的参数组成一条子命令,如若该子命令的Exit Status为0(表示真),则举行then前边的子命令上,借使Exit Status非0(表示假),则实践elif、else恐怕fi后边的子命令。if前边的子命令经常是测量试验命令,但也能够是别的命令。Shell脚本未有{}括号,所以用fi表示if语句的利落。见下例:

        #! /bin/sh
      
        if [ -f /bin/bash ]
        then
            echo "/bin/bash is a file"
        else
            echo "/bin/bash is NOT a file"
        fi
        if :; then echo "always true"; fi
      
    • ":"是叁个特种的一声令下,称为空命令,该命令不做其它交事务,但Exit Status总是真。其余,也足以实施/bin/true或/bin/false获得真或假的Exit Status。再看贰个事例:

        #! /bin/sh
      
        echo "Is it morning? Please answer yes or no."
        read YES_OR_NO
        if [ "$YES_OR_NO" = "yes" ]; then
            echo "Good morning!"
        elif [ "$YES_OR_NO" = "no" ]; then
            echo "Good afternoon!"
        else
            echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
            exit 1
        fi
        exit 0
      
    • 上例中的read命令的职能是之类顾客输入一行字符串,将该字符串存到多少个Shell变量中。

    • 除此以外,Shell还提供了&&和||语法,和C语言类似,具备Short-circuit天性,比相当多Shell脚本喜欢写成这样:

        test "$(whoami)" != 'root' && (echo you are using a non-privileged account; exit 1)
      
    • &&相当于“if...then...”,而||相当于“if not...then...”。&&和||用于连接三个指令,而地点讲的-a和-o仅用于在测量检验表达式中一连四个测量试验条件,要留意它们的分别,举个例子:

        test "$VAR" -gt 1 -a "$VAR" -lt 3
      
    • 和以下写法是等价的

        test "$VAR" -gt 1 && test "$VAR" -lt 3
      
  • case/esac

    • case命令可类比C语言的switch/case语句,esac表示case语句块的甘休。C语言的case只可以协作整形或字符型常量表明式,而Shell脚本的case可以相称字符串和Wildcard,每一种相称分支能够有多少条命令,末尾必需以;;截至,实践时找到第二个相当的分层并试行相应的授命,然后径直跳到esac之后,没有要求像C语言同样用break跳出。

        #! /bin/sh
      
        echo "Is it morning? Please answer yes or no."
        read YES_OR_NO
        case "$YES_OR_NO" in
        yes|y|Yes|YES)
            echo "Good Morning!";;
        [nN]*)
            echo "Good Afternoon!";;
        *)
            echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
            exit 1;;
        esac
        exit 0
      
    • 运用case语句的例子能够在系统服务的脚本目录/etc/init.d中找到。这一个目录下的本子多数具备这种情势(以/etc/init.d/nfs-kernel-server为例):

        case "$1" in 
            start)
                ...
            ;;
            stop)
                ...
            ;;
            status)
                ...
            ;;
            reload | force-reload)
                ...
            ;;
            restart)
                ...
            ;;
            *)
                log_sucess_msg "Usage: nfs-kernel-server {start|stop|status|reload|force-reload|restart}"
                exit 1
            ;;
        esac
      
    • 起步nfs-kernel-server服务的命令是

        $ sudo /etc/init.d/nfs-kernel-server start
      
    • $1是三个非凡变量,在奉行脚本时自动取值为率先个命令行参数,约等于start,所以步入start)分支试行有关的命令。同理,命令行参数钦定为stop、reload或restart能够进去其余分支推行甘休服务、重新加载配置文件或再一次起动服务的相干命令。

规格测量试验

  • 命令test或[可以测验三个尺度是或不是创制,假设测量检验结果为真,则该命令的Exit Status为0,假若测验结果为假,则下令的Exit Status为1(注意与C语言的逻辑表示正好相反)。譬如测验七个数的大大小小关系:

    $ var=2
    $ test $var -gt 1
    $ echo $?
    0
    $ test $var -gt 3
    $ echo $?
    1
    
  • 固然看起来很意外,但右边括号[实在是叁个限令的名字,传给命令的各参数之间应当用空格隔开,举个例子:$VA奇骏、-gt、3、]和[一声令下的多个参数,它们之间必得用空格隔离。命令test或[的参数格局是同等的,只然则test命令不要求]参数。以[一声令下为例,常见的测量试验命令如下表所示:

    [ -d DIR ]                 如果DIR存在并且是一个目录则为真
    [ -f FILE ]                如果FILE存在且是一个普通文件则为真
    [ -z STRING ]              如果STRING的长度为零则为真
    [ -n STRING ]              如果STRING的长度非零则为真
    [ STRING1 = STRING2 ]      如果两个字符串相同则为真
    [ STRING1 != STRING2 ]     如果两个字符串不相同则为真
    [ ARG1 OP ARG2 ]           ARG1和ARG2应该是整数或者取值为整数的变量,
                               OP的值有:
                                    -eq     等于
                                    -ne     不等于
                                    -lt     小于
                                    -le     小于等于
                                    -gt     大于
                                    -ge     大于等于
    
  • 和C语言类似,测量检验条件之间还是能做与、或、非逻辑运算:

    [ ! EXPR ]           EXPR可以是上表中的任意一种测试条件, !表示"逻辑反(非)"
    [EXPR1 -a EXPR2 ]    EXPR1和EXPR2可以是上表中的任意一种测试条件,-a表示“逻辑与”
    [EXPR1 -o EXPR2 ]    EXPR1和EXPR2可以是上表中的任意一种测试条件,-o表示“逻辑或”
    
  • 例如:

    $ VAR=abc
    $ [ -d Desktop -a $VAR = 'abc' ]
    $ echo $?
    0
    
  • 只顾,若是上例中的$VARAV4变量事先未有定义,则被Shell张开为空字符串,会招致测验条件的语法错误(展开为[ -d Desktop -a = 'abc']),作为一种好的Shell编制程序习贯,应该总是把变量取值放在双引号之中(展开为[ -d Desktop -a "" = 'abc'])

    $ unset VAR
    $ [ -d Desktop -a $VAR = 'abc' ]
    -bash: [: 参数太多
    $ [ -d Desktop -a "$VAR" = 'abc' ]
    $ echo $?
    1
    

循环

  • for/do/done

    • Shell脚本的for循环结会谈C语言很不雷同,它相仿于一些编制程序语言foreach循环。比方:

        #! /bin/sh
      
        for FRUIT in apple banana pear; do
            echo "I like $FRUIT"
        done
      
    • FRUIT是二个循环变量,第一回循环$FRUIT的取值是apple,第三次取值是banana,第一回取值是pear。再譬如说,要将当前目录下的chap0、chap1、chap2等文件夹名改为chap0~、chap1~、chap2~等(按惯例,末尾有~字符的文件名代表不时文件),这一个命令能够这么写:

        $ for FILENAME in chap?; do mv $FILENAME $FILENAME~; done
      
    • 也能够那样写:

        $ for FILENAME in `ls chap?`; do mv $FILENAME $FILENAME~; done
      
  • while/do/done

    • while的用法和C语言类似。比方八个验证码的脚本:

        #! /bin/sh
      
        echo "Enter password:"
        read TRY
        while [ "$TRY" != "secret" ]; do
            echo "Sorry, try again"
            read TRY
        done
      
    • 上边包车型大巴例证通过算术运算调控循环的次数:

        #! /bin/sh
      
        COUNTER=1
        while [ "$COUNTER" -lt 10 ]; do
            echo "Here we go again"
            COUNTER=$[$COUNTER+1]
        done
      
    • 另,Shell还会有until循环,类似C语言的do...while。如有兴趣可在课后自动扩展学习。

  • break和continue

    • break[n]可以钦点跳出几层循环;continue跳过此次巡回,但不会跳出循环。
    • 即break跳出,continue跳过。
    • 演习:将地点表达密码的程序修改一下,要是客商输错伍回密码就报错退出。

分支

  • if/then/elif/else/fi

    • 和C语言类似,在Shell中用if、then、elif、else、fi这几条命令完毕分支调节。这种流程序调节制语句本质上也是由若干条Shell命令组成的,比方在此之前讲过的

      if [ -f ~/.bashrc ]; then
          . ~/.bashrc
      fi
      
    • 实际是三条命令,if [ -f ~/.bashrc ]是首先条,then . ~/.bashrc是第二条,fi是第三条。假如两条命令写在同一行则须求用;号隔离,一行只写一条命令就没有供给写;号了,别的,then后边有换行,但那条命令没写完,Shell会自动续行,把下一行接在then后边当作一条命令管理。和[一声令下一样,要留意命令和各参数之间必需用空格隔断。if命令的参数组成一条子命令,假设该子命令的Exit Status为0(表示真),则推行then前面的子命令上,假设Exit Status非0(表示假),则实施elif、else只怕fi前边的子命令。if前面包车型大巴子命令通常是测验命令,但也足以是另外命令。Shell脚本未有{}括号,所以用fi表示if语句的甘休。见下例:

      #! /bin/sh
      
      if [ -f /bin/bash ]
      then
          echo "/bin/bash is a file"
      else
          echo "/bin/bash is NOT a file"
      fi
      if :; then echo "always true"; fi
      
    • ":"是贰个分裂平时的授命,称为空命令,该命令不做其余交事务,但Exit Status总是真。其它,也得以推行/bin/true或/bin/false获得真或假的Exit Status。再看一个例证:

      #! /bin/sh
      
      echo "Is it morning? Please answer yes or no."
      read YES_OR_NO
      if [ "$YES_OR_NO" = "yes" ]; then
          echo "Good morning!"
      elif [ "$YES_OR_NO" = "no" ]; then
          echo "Good afternoon!"
      else
          echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
          exit 1
      fi
      exit 0
      
    • 上例中的read命令的效用是之类客商输入一行字符串,将该字符串存到三个Shell变量中。

    • 别的,Shell还提供了&&和||语法,和C语言类似,具备Short-circuit个性,比很多Shell脚本喜欢写成这么:

      test "$(whoami)" != 'root' && (echo you are using a non-privileged account; exit 1)
      
    • &&也正是“if...then...”,而||也便是“if not...then...”。&&和||用于连接五个指令,而地点讲的-a和-o仅用于在测量试验表明式中年老年是三个测量试验条件,要潜心它们的分别,举个例子:

      test "$VAR" -gt 1 -a "$VAR" -lt 3
      
    • 和以下写法是等价的

      test "$VAR" -gt 1 && test "$VAR" -lt 3
      
  • case/esac

    • case命令可类比C语言的switch/case语句,esac表示case语句块的告竣。C语言的case只好同盟整形或字符型常量表明式,而Shell脚本的case能够相称字符串和魏尔德card,每一个相配分支能够有多少条命令,末尾必需以;;停止,实行时找到第叁个门户相当的支行并推行相应的指令,然后直接跳到esac之后,无需像C语言同样用break跳出。

      #! /bin/sh
      
      echo "Is it morning? Please answer yes or no."
      read YES_OR_NO
      case "$YES_OR_NO" in
      yes|y|Yes|YES)
          echo "Good Morning!";;
      [nN]*)
          echo "Good Afternoon!";;
      *)
          echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
          exit 1;;
      esac
      exit 0
      
    • 应用case语句的事例能够在系统服务的脚本目录/etc/init.d中找到。这么些目录下的本子多数具备这种样式(以/etc/init.d/nfs-kernel-server为例):

      case "$1" in 
          start)
              ...
          ;;
          stop)
              ...
          ;;
          status)
              ...
          ;;
          reload | force-reload)
              ...
          ;;
          restart)
              ...
          ;;
          *)
              log_sucess_msg "Usage: nfs-kernel-server {start|stop|status|reload|force-reload|restart}"
              exit 1
          ;;
      esac
      
    • 运转nfs-kernel-server服务的一声令下是

      $ sudo /etc/init.d/nfs-kernel-server start
      
    • $1是一个出奇变量,在奉行脚本时自动取值为率先个命令行参数,也等于start,所以步入start)分支实行有关的一声令下。同理,命令行参数内定为stop、reload或restart能够进来其余分支实行甘休服务、重新加载配置文件或再一次启航服务的连锁命令。

本文由威尼斯国际官方网站发布于电脑知识,转载请注明出处:【威尼斯国际官方网站】Shell编程

关键词: