一.Shell介绍shell是一个命令行解释器,脚本语言,活动在应用程序与内核之间,用于接收应用程序(用户)命令,调用操作系统内核。

(1)编译型语言:

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

程序在执行之前需要个专门的编译过程,把程序编译成为机器语言文件,运行时不需要重新翻译,直接使用编译的结果就行了。程序执行效率高,依养编译器,跨平台性差些。如C、C++、java

(2)解释型语言:

程序不需要编译,程序在运行时由解释器翻译成机器语言,每执行一次都要翻译一次。因此效率比较低。比如Python/javaScript/Shell等都是解释型语言。

 

二、Shell解析器

(1)Linux提供的Shell解析器有:

 

[root@Linux01 home]#  cat /etc/shells
 /bin/sh    是bash的一个快捷方式 
 /bin/bash   bash是大多数Linux默认的shell,包含的功能几乎可以涵盖shell所有的功能
 /sbin/nologin  表示非交互,不能登录操作系统
 /bin/dash  小巧,高效,功能相比少一些
 /bin/tcsh  具有C语言风格的一种shell,具有许多特性,但是也有一些缺陷
  /bin/csh   是csh的增强版本,完全兼容csh

 

(2)bash和sh的关系:

[root@Linux01 bin]#  ll  | grep bash
-rwxr-xr-x. 1 root root 942200 3月 23 2017 bash
lrwxrwxrwx. 1 root root 4 6月 29 19:35 sh -> bash

(3)Centos默认的解析器是bash

[root@Linux01 bin]#  echo $SHELL
/bin/bash

 

三、Shell脚本入门

一句话概括:简单来说脚本就是将需要执行的命令保存到文本中,按照顺序执行(由上往下执行),它是解释型的,不需要编译。

1.脚本格式

脚本以#!/bin/bash或者#!/bin/env bash开头(指定解析器)

脚本中间写注释信息内容,单行注释#  多行注释 :<<EOF   EOF       注释内容如下:

<<EOF
name:second-shell.sh
desc:创建文件,在文件中添加内容,打印信息
update:2020-07-02
path:/home
EOF

然后写脚本内容

2.第一个Shell脚本:输出helloworld

(1)需求:创建一个Shell脚本,输出helloworld

(2)案例实操:

[jinghang@hadoop101 datas]$ touch helloworld.sh

[jinghang@hadoop101 datas]$ vi helloworld.sh

 在helloworld.sh中输入如下内容

#!/bin/bash

echo "helloworld"

运行脚本,会输出 helloWord

  3、脚本的常用执行方式

第一种

采用bash或sh+脚本的相对路径或绝对路径(不用赋予脚本+x权限)

       sh+脚本的相对路径

[jinghang@hadoop101 datas]$ sh helloworld.sh

Helloworld

       sh+脚本的绝对路径

[jinghang@hadoop101 datas]$ sh /home/jinghang/datas/helloworld.sh

helloworld

       bash+脚本的相对路径

[jinghang@hadoop101 datas]$ bash helloworld.sh

Helloworld

       bash+脚本的绝对路径

[jinghang@hadoop101 datas]$ bash /home/jinghang/datas/helloworld.sh

Helloworld

第二种

采用输入脚本的绝对路径或相对路径执行脚本(必须具有可执行权限+x,推荐采用这种方式)

(a)首先要赋予helloworld.sh 脚本的+x权限

[jinghang@hadoop101 datas]$ chmod +x helloworld.sh

(b)执行脚本

相对路径

[jinghang@hadoop101 datas]$ ./helloworld.sh

Helloworld

绝对路径

[jinghang@hadoop101 datas]$ /home/jinghang/datas/helloworld.sh

Helloworld

注意:第一种执行方法,本质是bash解析器帮你执行脚本,所以脚本本身不需要执行权限。第二种执行方法,本质是脚本需要自己执行,所以需要执行权限

4、查看脚本的执行流程(一般使用这个命令来查看脚本执行的步骤)

[jinghang@hadoop101 datas]$ bash -x  batch.sh

5、查看脚本的语法(一般使用这个命令来检查脚本语法错误)

[jinghang@hadoop101 datas]$ bash -n  batch.sh

 

4、shell变量:变量是用来临时保存数据的,该数据是可以变化的数据

  1. 读取Shell中所有变量命令:set    读取环境变量:env
  2. 系统变量
    a)$HOME、$PWD、$SHELL、$USER
    b)读取变量:echo $变量名

  3. 自定义变量
    a)用户变量
        作用域(只在当前会话的当前用户下有效)
        定义变量:
            变量名=值
            变量名=`执行命令`
            变量名=$(执行命令)
        读取变量:echo $变量名
              echo ${A:2:3}  (切片,读取变量几位,索引从0开始,第一个冒号后面代表索引开始位置,第二个冒号后面代表读取几位)
              echo ${A}
              echo $A
        撤销变量:unset 变量名
        静态变量(一旦创建,只可读,不能unset): readonly 变量名=值
        定义有类型的变量
            目的:给变量做一些限制,固定变量的类型
            语法:declare 选项 变量名=变量值
            常用选项
                -i 将变量看作整数
                -r 创建只读变量
    b)全局环境变量
        作用域(针对于当前会话下的所有用户有效)
        关键字:export
        定义变量:export 变量名=值
        撤销和读取同上
    c)系统环境变量
        作用域(针对于所有会话下的所有用户都有效)
        编辑配置文件:vim /etc/profile
            例如添加系统环境变量 MYNAME=jinghang
                #系统环境变量
                export MYNAME=jinghang
       变量生效:source /etc/profile
           
       经验技巧:
        (1)变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写。
        (2)等号两侧不能有空格
        (3)在bash中,变量默认类型都是字符串类型,无法直接进行数值运算。
        (4)变量的值如果有空格,需要使用双引号或单引号括起来。

  4. 特殊变量

             a)$n
    语法:$n (功能描述:n为数字,$0代表该脚本名称,$1-$9代表第一到第九个参数,十以上的参数,十以上的参数需要用大括号包含,如${10})
  b)$#
    语法:$# (功能描述:获取所有输入参数个数,常用于循环)
  c)$*
    语法:$* (功能描述:这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体)
  d)$@
    语法:$@ (功能描述:这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待)
  e)$?
    语法:$? (功能描述:最后一次执行命令的返回状态。如果值为0,命令正确执行;如果值为非0(具体是哪个数,由命令自己来决定),则命令执行不正确)

5、shell数组

  • 定义:

        Shell 数组用括号来表示,元素用"空格"符号分割开,如果元素中包含空格,则该元素使用双引号引起来,例如"hello word"

  • 语法:

        往数组里添加值,数组的长度自增,元素索引从0开始
        数组名=(value1 value2 value3)

  • 赋值:

        创建时添加 数组名=(A B "C B" D)
        创建后添加 数组名[4]=E

  • 修改:

        局部:根据索引修改数组   例如:数组名[0]=F
        整体:可以直接给数组变量重新赋值

  • 读取:

        获取数组中所有的元素:echo ${数组名[*]} 或者 echo ${数组名[@]}
        根据索引读取数组元素:echo ${数组名[索引值]}
        获取数组的长度:echo ${#数组名[*]} 或者 echo ${#数组名[@]}

  • 删除:

        unset 关键字来删除数组元素,格式如下:
            unset  数组名[index]
        不写下标,删除整个数组,格式如下:
            unset 数组名

 

6、Shell中的运算符

  • 整数运算语法(默认):

    (1)$(( 运算式 ))   或  $[运算式] 
    (2)运算符   + , - , *, /, %   加,减,乘,除,取余

    (3)运算式要与小扩号之间有空格,中括号的话不用加空格

 (4)expr + , - , \*, /, % 加,减,乘,除,取余   注意:expr表达式运算符间要有空格   例如 expr $A  +  $B

  • 小数运算:

        bc:Linux下的一个计算器程序,可以处理整数和小数。Shell 本身只支持整数运算,想计算小数就得使用 bc 这个外部的计算器
        在 Shell 脚本中,借助管道或者输入重定向来使用 bc 计算器。
        语法:echo "scale=要保留的小数位数 ; 计算式" | bc
            expression就是希望计算的数学表达式
        案例1:计算3*8/7 结果保留4位小数
            echo "scale=4; 3*8/7" | bc
        案例2:计算3*8/7 ,再乘5,结果保留3位小数
            echo "scale=3; 3*8/7*5" | bc
        案例4:计算4/9,保留2位,结果赋值给ret变量
            ret=$(echo "scale=2;4/9" | bc)

 

7、Shell条件判断

  • 语法:

        注意:条件非空即为true,[ 判断式 ]返回true,[判断式] 返回false。[ 判断式 ](注意判断式前后要有空格)

  • 常用条件判断

    (1)两个整数之间比较
            = 字符串比较
            -lt 小于(less than)
            -le 小于等于(less equal)
            -eq 等于(equal)
            -gt 大于(greater than)
            -ge 大于等于(greater equal)
    -ne 不等于(Not equal)
    (2)按照文件权限进行判断
      -r 有读的权限(read)
      -w 有写的权限(write)
      -x 有执行的权限(execute)
    (3)按照文件类型进行判断
      -f 文件存在并且是一个常规的文件(file)
      -e 文件存在(existence)
      -d 文件存在并是一个目录(判断目录)(directory)

  • 案例:

        多条件判断(&& 表示前一条命令执行成功时,才执行后一条命令,|| 表示上一条命令执行失败后,才执行下一条命令)
            [jinghang@hadoop101 ~]$ [ condition ] && echo OK || echo NOTOK
            OK
            [jinghang@hadoop101 ~]$ [ condition ] && [ ] || echo NOTOK
            NOTOK

 

8、Shell流程控制 

  • if 判断语句

        注意事项:
        (1)[ 条件判断式 ],中括号和条件判断式之间必须有空格
        (2)if后要有空格

        语法1:
            if [ 条件判断式 ]
            then
                主体代码
            fi
        语法2:
            if [ 条件判断式 ]
            then
                主体代码
            else
                主体代码
            fi
        语法3:
            if [ 条件判断式 ]
            then
                主体代码
            elif [条件判断式]
            then
                主体代码
            else
                主体代码
            fi

  • case 判断语句

        基本语法:
            case $变量名 in
                    "值1")
                    如果变量的值等于值1,则执行程序1
                    ;;
                    "值2")
       如果变量的值等于值2,则执行程序2
          ;;
          …省略其他分支…
                    *)
                    如果变量的值都不是以上的值,则执行此程序
                     ;;
              esac
        注意事项:
             1)case行尾必须为单词“in”,每一个模式匹配必须以右括号“)”结束。
        2)双分号“;;”表示命令序列结束,相当于java中的break。
        3)最后的“*)”表示默认模式,相当于java中的default。

  • for 循环语句

        基本语法:
      语法一
          for  (( 初始值;循环控制条件;变量变化 ))
     do
                  逻辑代码
          done
      语法二
                $* : 读取传入脚本中的全部参数,把参数看作一个整体
                $@ : 读取传入脚本中的全部参数,把参数区分对待

 

                    for 变量 in "$*或者$@"
                    do
                         逻辑代码
                    done

      注意:for 与 ( 号之间要有空格

  • while 循环语句

        基本语法
      while [ 条件判断式 ]
      do
          逻辑代码
      done
  注意:While 与 [ 号之间要有空格

 

9、read读取控制台输入

  • 基本语法:read 【选项】【参数】

      选项
          -p 指定读取值时的提示符;
          -t 指定读取值时等待的时间(秒);
      参数:指定读取值的变量名

  • 案例

      1、请在3秒内输入用户名 

 

      [root@Linux01 home]# read -p "请在3秒内输入用户名:" -t 3 name
      请在3秒内输入用户名:zhangsan

  2、通过read定制菜单栏

      cat <<-EOF

     1:代表对数据进行倒序排列
      2:代表对数据进行正序排列
     
EOF
      read -p "请在20秒内输入数字:" -t  20 num

 

 

10、Shell函数  

  •  系统函数

      basename
          basename 命令会删掉所有的前缀包括最后一个(‘/’)字符,然后将字符串显示出来(去掉路径,只显示最后的文件名)
          例如:[root@Linux01 home]# basename /home/test/ccc.txt
          ccc.txt

      dirname
          从给定的包含绝对路径的文件名中去除文件名,然后返回剩下的路径(去掉文件名,只显示文件名之前的绝对路径)
          例如:[root@Linux01 home]# dirname /home/test/ccc.txt
           /home/test

  •  自定义函数

        语法:
      function 函数名()
      {
     方法体
          [return int;]
      }

        编写完脚本之后,执行脚本,就能调用函数了,直接输函数名就可以(在外部调用);在脚本内部调用函数直接函数名就可以。
  经验技巧
        (1)必须在调用函数地方之前,先声明函数,shell脚本逐行运行。不会先编译。
        (2)函数返回值,只能通过$?系统变量获得,可以显示加:return返回,如果不加,将以最后一条命令运行结果,作为返回值。return后跟数值n(0-255)
      创建用户函数(只能当前用户调用)

    1.在用户的家目录中(/home/用户名)找到隐藏文件.bashrc进行编写函数

    2.source  .bashrc

    3.现在就能直接调用函数了

   创建系统函数(所有用户和会话可调用,重启后仍可调用)

    1.root用户在/etc/bashrc文件下编写函数

    2、source  /etc/bashrc

    3.所有用户都可直接调用

 

 

11、 shell文本处理工具

  •  cut(查看)

        功能描述:cut的工作就是“剪”,具体的说就是在文件中负责剪切数据用的,cut指令用于显示行中的指定部分,删除文件中的指定字段。
        语法:cut 【选项】【文件】
        选项 
            -b <起始字节位置-结束字节位置> 仅显示行中指定字节范围的内容。例如,“-b 2-10”将显示第2~10个字节位置的内容,当只有一个数字时,则仅显示指定字符位置的内容.
            -f <起始列位置-结束列位置> 显示指定列的字段内容
            -d <分隔符> 指定字段的分隔符,默认的字段分隔符为“TAB”
            -c <起始字符位置-结束字符位置> 仅显示行中指定范围的字符。例如,“b2-10” 将显示第2~10个字符位置的内容。当只有一个数字时,则仅显示指定字符位置的内容
   案例:
    切割ifconfig 后打印的IP地址,显示ip地址前3位
      ifconfig eth0 | grep "inet addr" | cut -d : -f 2 | cut -d " " -f 1 | cut -c 1-3

  • sort(查看)

  功能描述:它将文件进行排序,并将排序结果标准输出
  语法:sort 【选项】【参数】
      选项
          -n 依照数值的大小排序
          -r 以相反的顺序来排序
          -t 设置排序时所用的分隔字符
          -k 指定需要排序的列
      参数:是指待排序的文件
  案例:
    将用户列表按照主ID进行倒序排列

    [mayun@Linux01 home]$  sort -t : -nrk 4 /etc/passwd

 

  • 正则表达式

  概述:正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE)。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本
  单字符匹配
    \d 匹配一个数字字符。等价于[0-9]
    \D 匹配一个非数字字符。等价于[^0-9]
    \w 匹配包括下划线的任何单词字符。类似但不等价于[A-Za-z0-9_]
    \W 匹配任何非单词字符。等价于 [^A-Za-z0-9_]
    \s 匹配空白字符,包括空格、制表符、换页符等等,等价于[ \f\n\r\t\v]
    \S 匹配任何可见字符。等价于[^ \f\n\r\t\v]
    .点 匹配除“\n”和"\r"之外的任何单个字符
    [a-z] 字符范围,匹配a~z之间的任意字符
    [^a-z] 匹配除了a~z之间的其他字符
    \n 匹配换行符
  多字符匹配
    + 匹配前面的子表达式一次或多次(大于等于1次)
    * 匹配前面的子表达式任意次
    ? 匹配前面的子表达式零次或一次
    {n} n是一个非负整数。匹配确定的n次
    {n,m} m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次
  其他
    ^ 匹配输入字行首
    $ 匹配输入行尾
    | 将两个匹配条件进行逻辑“或”(or)运算
      x|y 匹配x或y

  贪婪模式:贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配   例如: [a-b]*表达式去匹配字符串ababababababbaba,就会全部匹配上

  非贪婪模式:在整个表达式匹配成功的前提下,尽可能少的匹配      例如:[a-b]*?表达式去匹配字符串ababababababbaba,就只会匹配ab

  •  sed

  功能描述:sed是一种单行文本流式编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件结束。文件内容并没有改变,除非你使用重定向存储输出。
  语法:sed [选项]  ’命令‘    文件名
  选项 功能
    -e 直接在指令列模式上进行sed的动作编辑(一次执行多个操作时)。
    -i 直接编辑文件(修改源文件)
  命令 功能
    p 打印一般 -n 配合使用
    a 新增,在指定的行之后插入内容
    i 新增,在指定的行之前插入内容
    d 删除
    s 查找并替换 (注意:如果进行全局的查找替换 sed  -e  's/查找条件/替换字符串/g' )
  案例:
  数据准备
  (1)将“mei nv”这个单词插入到sed.txt第二行下
    sed  -e '2a mei nv' sed.txt
  (2)删除sed.txt文件所有以wo开头的行
    sed  -e '/^wo/d' sed.txt
  (3)将sed.txt文件中wo替换为ni
    sed  -e  's/wo/ni/g'  sed.txt
    注意:‘g’表示global,全部替换
  (4)将sed.txt文件中的第二行删除并将wo替换为ni
    sed -e '2d'  -e  's/wo/ni/g'  sed.txt
  (5)打开文件注释单行注释的行(删掉第一个#号)
    sed -e  's/^#//g'  sed.txt
   (6) 给文件的前5行内容添加注释
    sed  -e  '1,5s/^/#/g' sed.txt

  •  awk

  功能描述:是一门编程语言,也是一个强大的文本分析工具,逐行扫描文件,默认从第一行到最后一行,寻找匹配特定模式的行,并在这些行上进行你想要的操作。
  语法:awk 选项 'pattern1{action1} pattern2{action2}...' 文件名
  pattern:表示AWK在数据中查找的内容,就是匹配模式,正则表达式
  action:在找到匹配内容时所执行的一系列命令
  选项 功能
    -F 指定输入文件折分隔符
    -v 赋值一个用户定义变量
  案例:
    (1)搜索passwd文件以root关键字开头的所有行,并输出该行的第7列。
        awk -F : '/^root/{print $7}' passwd
    (2)搜索passwd文件以root关键字开头的所有行,并输出该行的第1列和第7列,中间以“,”号分割。
        awk -F : '/^root/{print $1","$7}' passwd
        注意:只有匹配了pattern的行才会执行action
    (3)只显示/etc/passwd的第一列和第七列,以逗号分割,且在所有行前面添加列名user,shell在最后一行添加"总用户数:用户数量"。
        awk -F : 'BEGIN{sum=0;print "user, shell"} {sum=sum+1;print $1","$7} END{print "总用户为:"sum}' passwd

        或者awk -v  sum=0  -F : 'BEGIN{print "user, shell"} {sum=sum+1;print $1","$7} END{print "总用户为:"sum}' passwd
        注意:BEGIN 在所有数据读取行之前执行;END 在所有数据执行之后执行。
    (4)将passwd文件中的用户id增加数值1并输出计算后的用户id和用户名
        awk -v i=1 -F : '{print $1 "," $3+i}' passwd
  awk的内置变量
    变量 说明
      FILENAME 文件名
      NR 已读的记录数
      NF 浏览记录的域的个数(切割后,列的个数)
    案例:
    (1)统计passwd文件名,每行的行号,每行的列数
        awk -F: '{print "filename:" FILENAME ", linenumber:" NR ",columns:" NF}' passwd
    (2)切割IP
        ifconfig eth0 | grep "inet addr" | awk -F: '{print $2}' | awk -F " " '{print $1}'
    (3)查询sed.txt中空行所在的行号
        awk '/^$/{print NR}' sed.txt

 

 

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄