shell脚本

        Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。

        Shell 是指一种应用程序,一种和内核沟通的外壳应用程序的统称。这个应用程序有时提供了一个界面,用户通过这个界面访问操作系统内核的服务。

          bash是shell中的佼佼者。我们一般说的shell是指shell脚本。

1、shell的特点

       解释非编译型。

       弱类型。

       执行模式:交互式/批处理式。

2、shell脚本

      (1)shell脚本的运行方式

       shell脚本的文件一般都是以.sh结尾的。

       shell脚本文件的开头一般都会写上 #!/bin/bash 。#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。通常,(#!)的名称,叫做”Shebang”或者”Sha-bang”(蛇棒)。

        echo 命令用于向窗口输出文本。

shell脚本一般有两种执行方式:作为可执行程序或者作为解释器的参数。


      作为第一种方式执行时,注意,一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./test.sh 告诉系统说,就在当前目录找。

      作为第二中方式执行时,这种运行方式是,直接运行解释器,其参数就是 shell 脚本的文件名,这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。

     Shell脚本中用#表示注释,相当于C语言的//注释。

     但如果#位于第一行开头,并且是则例外,它表示该脚本使用后面指定的解释器/bin/bash解释执行。

      (2)shell执行方式的原理

  • 第一种执行方式: chmod +x test.sh Shell会fork一个子进程并调用exec执行./test.sh这个程序,exec系统调用应该把子进程的代码段替换成./test.sh程序的代码段,并从它的_start开始执行。
  • 然而test.sh是个文本文件,根本没有代码段和_start函数! 怎么办呢? 其实exec还有另外一种机制,如果要执行的是一个文本文件,并且第一行用Shebang指定了解释器,则用解释器程序的代码段替换当前进程,并且从解释器的 _start开始执行,而这个文本文件被当作命令行参数传给解释器。
  • 交互Shell(bash)fork/exec一个子Shell(sh)用于执行脚本,父进程bash等待子进程sh终止
  • sh读取脚本中的cd ..命令,调用相应的函数执行内建命令,改变当前工作目录为上一级目录
  • sh读取脚本中的ls命令,fork/exec这个程序,列出当前工作目录下的文件,sh等待ls终止
  • ls终止后,sh继续执行,读到脚本文件末尾,sh终止。
  • sh终止后,bash继续执行,打印提示符等待用户输入。

   (3)shell的内置命令

       脚本执行cd命令,发现回显消息当前所处的目录发生改变,但实际上,真实目录并没有改变。这个也很好理解,毕竟要创建子进程来解释脚本。但是:直接命令行上执行cd 命令,发现父bash的工作目录发生了改变!这个如何理解?说好的创建子进程呢?归根结底,执行命令,不一定要创建子进程!这些不需要创建子进程的命令,叫做shell的内置命令,由父bash亲自执行,理解上,将该类命令,理解成shell的内部函数即可。

      用.或者source修饰脚本,脚本的执行影响到了父bash!source或者.命令是Shell的内建命令,这种方式也不会创建子Shell,而是直接在交互式Shell下逐行执行脚本中的命令。

 3、shell变量

      shell是弱类型语言,原则上,不是特别强调shell变量,或者shell变量可以放很多常见内容,这点和传统的C/C++有很大不同。shell变量也不需要提前定义,或者不牵扯到定义一说,需要时直接使用即可。

 (1)赋值和命名规则

      shell变量的赋值直接将所要赋值的值用引号引起来直接用等号赋值就行。

      例如:c="hello world"。

   需要注意,变量名和等号之间不能有空格! 否则会被Shell解释成命令和命令行参数。 同时,变量名的命名须遵循如下规则:

  • 首个字符必须为字母(a-z,A-Z)。
  • 中间不能有空格,可以使用下划线(_)。
  • 不能使用标点符号。
  • 不能使用bash里的关键字(可用help命令查看保留关键字)。

    所有的变量不需要先定义后使用,而是直接使用。

  (2)变量的使用

       在使用一个赋值过的变量,只要在变量名前面加美元符号即可,如:echo $c

有时候,我们想要同时输出一个变量和和一个字符串组合的内容时,会出错,因此我们就需要给变量带个{}作为变量名的边界。

   (3)只读变量

         使用readonly命令可以将变量定义为只读变量,只读变量的值不能被修改。

   (4)删除变量

        使用unset命令就可以删除变量。unset + 变量名

         被删除的变量,内容会被清空,一般也是不在被使用的变量需要unset,unset 命令不能删除只读变量。

   (5)变量类型

        也许在你看来shell脚本的基本语法之后,你可能会有点郁闷,shell不是弱类型的吗?怎么还有类型?这里说的类型不是我们所说的一般类型,和C++变量类型不一样。

  • 本地变量: 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。   
  • 环境变量: 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
  • shell变量: shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行。

   测试用例:


       我们在父shell上定义了一个变量,直接在交互式父shell中访问时可以直接访问的,但是在子脚本中,却没有访问到,因此,我们将val变量导出变为环境变量,发现就可以直接显示出来。

       由此我们看出:

     1)本地变量值存在于当前shell进程,用set命令可以显示当前shell进程中定义的所有变量(包括本地变量和环境变量)和函数。上述测试用例中,val在没有被导出的时候,就是父shell内的一个本地变量,环境变量时任何进程都有的概念,而本地变量时shell特有的概念。

     2)环境变量可以从父进程传给子进程,因此shell内的环境变量可以从当前进程传给fork出的子进程,用printenv命令可以显示当前shell进程的环境变量

    (6)字符串的操作

         1)拼接字符串

    在shell脚本中,想要将字符串进行拼接只需要将信息卸载一起即可,但是也有一些例外。

    比如想要将两个变量和一个字符串卸载一起就需要给两个变量名前都加上$符号,字符串就要加上引号区别一下。

       

         2)获取字符串长度

       

         3)提取子字符串

        

         4)查找子字符串

     (7)文件名代换 (Globbing )::* ? []

  • 通配符 * : 匹配0个或多个任意字符
  • ? : 匹配一个任意字符
  • [若干字符] : 匹配方括号中任意一个字符的一次出现

               

         (8)命令代换和算数代换

         由反引号``括起来的也是一条命令,Shell先执行该命令,然后将输出结果立刻代换到当前命令行中。

           命令代换也可以用$() 表示: DATE=$(date +%Y:%m:%d)

           (()) 中的shell变量取值将转换成整数,常用于算术计算。

         

           如果要对运算结果进行赋值或者作为右值

        

          (())中只能用+-*/和()运算符,并且只能做整数运算。

         (9)转义字符

         和C语言类似,\在Shell中被用作转义字符,用于去除紧跟其后的单个字符的特殊意义(回车除外),换句话说,紧跟其后的字符取字面值。另外,\还可以紧跟其后的普通字符取特殊含义。

         比如创建和删除一个文件名为$ $ (中间有空格)的文件可以这样:

         

         另外,还有一个字符虽然不具有特殊含义,但是要用它做文件名也很麻烦,就是- 号。如果要创建一个文 件名以- 号开头的文件,这样是不行的: 即使加上\ 转义也还是报错: 因为各种UNIX命令都把- 号开头的命令行参数当作命令的选项,而不会当作文件名。如果非要处理以- 号开头的文件名,可以有两种办法:

          

        \还有一种用法,在\后敲回车表示续行,Shell并不会立刻执行命令,而是把光标移到下一行,给出 一个续行提示符>,等待用户继续输入,最后把所有的续行接到一起当作一个命令执行。例

        (10)单引号双引号

       和C语言不一样,Shell脚本中的单引号和双引号一样都是字符串的界定符,而不是字符的界定符。单引号用于保持引号内所有字符的字面值,即使引号内的\和回车也不例外, 但是字符串中不能出现单引号。如果引号没有配对就输入回车,Shell会给出续行提示符,要求用户把引号配上对。

  双引号用于保持引号内所有字符的字面值(回车也不例外),但以下情况除外:

  • $ 加变量名可以取变量的值
  • 反引号仍表示命令替换
  • $表示$的字面值
  • `表示`的字面值(反引号)
  • \"表示"的字面值
  • \表示\的字面值 除以上情况之外,在其它字符前面的\无特殊含义,只表示字面值




  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值