Linux学习12-shell环境与脚本基础

shell脚本编程基础

关于shell script

shell script是利用shell的功能所写的一个程序(program),这个程序是使用纯文本文件,将一些shell的语法与指令(含外部指令)写在里面,搭配正则表达式、管线命令与数据流重导向等功能,让使用者能够one touch的方法去处理复杂的动作,以达到我们所想要的处理目的。

知识点

  1. shell脚本基础
  2. 变量的定制和使用,以及修改配置文件
  3. 相关命令read、echo、export、declare

1. 定制或编写简单脚本

1.1 脚本基本格式

使用文本工具创建脚本文件,推介文本格式后缀为.sh非强制

  • 第一行:
    首行必须shebang机制(也就是#!跟上shell类型),声明这个脚本使用的shell名称。当这个程序被执行时,就能够加载bash的相关配置文件,使我们底下的指令能够执行。查看当前Linux系统可以使用的shells,可以检查/etc/shells文件

    #!/bin/bash   
    #!/usr/bin/python
    #!/usr/bin/perl
    
  • 批注:
    整个脚本中,除了第一行的#!是必须的之外,其他的以#开头的都可以理解为批注,来说明这个脚本的基本信息,可根据个人需要定制,推荐有以下内容

            #程序名称    
            #版本号
            #作者信息
            #更改时间
            #该程序的作用及注意事项
            #各版本的更新简要说明
    
  • 主要环境变量的说明
    将一些重要的环境变量设定好,提高脚本的灵活性。

  • 主要程序
    脚本内容,就是为达到脚本目的将语法与指令(含外部指令)写在里面。写较为特殊的代码时,加上批注,便于之后查阅

  • 执行结果(回传信息)
    将脚本执行结果回传给系统,显示脚本执行结果

1.2 脚本运行方法

  • 给与脚本执行权限,在命令行上指定脚本的绝对或相对路径
  • 将脚本放到PATH变量的文件夹中或者修改PATH变量将脚本路径加进去
  • 命令bash [script] 开启子进程运行,不影响当前运行环境
  • source或小数点(.) [script] 将配置文件读进当前的shell环境,影响当前的运行环境

1.3 脚本调试

  • 检测脚本中的语法错误
    bash -n /path/to/some_script
  • 调试跟踪执行
    bash -x /path/to/some_script

1.4 退出状态,判断程序执行结果

进程使用退出状态来报告成功或失败

命令:$?   保存了前一个执行结果
返回值0代表成功   , 1-255代表失败。保存最近的命令状态,也就是前一个命令的成功或失败

命令:exit [n]
自定义退出状态码,n可以给定数值,以根据返回值区别不同原因,包括0,范围为0-255。

命令:true和false
返回结果为总是成功与总是失败

1.5 算术运算

bash中不支持浮点运算,仅支持整数数据
运算符号:+、-、、/、%(取余)、*(乘方)
应 用:得到了退出状态返回值,通过算术运算判断结果

     通过例题来说明bash中的算术运算方法
     例如:运算1+2,赋值 x=1、y=2
     方法1: let  sum=x+y       echo  $sum        
     方法2: echo $[x+y]
     方法3: echo $((x+y))
     方法4: 命令expr     expr  1  +  2中间要加空格,特殊符号要转译
     方法5: declare   -i  x=1; declare   -i  y=2; sum=m+n; declare  -i   sum =x+y;  echo $sum  
     方法6: echo 1+2|bc
     方法7: ((s=10+20))    echo $s

     增强型赋值:+=、-=、*=、/=、%=
     n+=2 意思是  n=n+2  得用let定义先
     n++意思是 n=n+1
     n--意思是n=n-1


       例1:[root@V9centos7 /data]#n=10
           [root@V9centos7 /data]#let n+=2   <==先用let定义
           [root@V9centos7 /data]#echo $n
                 12                          <==运算结果

        例2:先++和后++是有区别的
            [root@V9centos7 /data]#n=10
            [root@V9centos7 /data]#let m=++n;echo $m
            11                      <==++先给n赋值
            [root@V9centos7 /data]#n=10
            [root@V9centos7 /data]#let m=n++;echo $m;echo $n
            10                      <== m先=n,n再赋值
            11

1.6 逻辑运算:真或假 1 或 0

与 关系(&)

        1与1=1    <==1代表真
        1与0=0
        0与1=0
        0与0=0

或关系(|)

        1或1=1
        1或0=1
        0或1=1
        0或0=0

非关系(!)
可以判断逻辑表达式,取反

        !1=0
        !0=1
 例:赋值a=10、b=10,判断是否相等[ $a -eq $b ],返回值echo $为0,[ ! $a -eq $b ]返回值echo $为1。

异或:(^)
相同为0,不同为1

 例1:12^8将数字转换成二进制
            12      1100   <==第1行
            08      1000   <==第2行
    异或     04      0100   <==行1与行2,上下对比,相同取0,不同取1

 例2:赋值a=15、b=10,调换a和b的值
    #a=$[a^b];b=$[a^b];a=$[a^b];echo $a $b
       (1)     (2)     (3)
     10 15                 <==结果
  PS:步骤(1)a和b异或得到中间值c,将a定义为c
      步骤(2)现在的a=c,也就是b=[c^b],得到b=a
      步骤(3)含义为[c^a],得到a=b

短路与 (&&)

      cmd1  &&  cmd2  如果命令1成功,则执行命令2;如果cmd1失败,则不执行cmd2

短路或(||)

       cmd1 || cmd2   如果命令1成功,则不执行命令2;如果cmd1失败,则执行cmd2

应用:利用逻辑关系达成判断式

    例1:判断IP地址是否连通,通则显示up,否则显示down
        #!/bin/bash     <==脚本第一行
        read -p "please input ip:" ip
        ip=${ip:-ip}     <==定义变量
        ping -c1 $ip &>/dev/null && echo $ip is up || echo $ip is down    <==利用或与逻辑关系达成判断式
    PS:指令是一个一个往后执行的,因此在上面的例子中,我们将关系式简写为(1)&&(2)||(3),第一部分执行结果如果回传$?≠0,则'&&'判断不执行第二部分,将$?≠0传递给'||'判断,则执行第三部分

    例2:承上例,写一个错误的逻辑关系以对比
         ping -c1 $ip &>/dev/null || echo $ip is down && echo $ip is up
         172.16.211.220 is down
         172.16.211.220 is up
    PS:第一部分执行回传结果若为$?≠0,经过'||'判断执行第二部分,第二部分必定是成功的,回传$?=0,经'&&'判断执行3。就同时出现了通与不通。

1.7 条件测试

逻辑处理需要配合测试命令,来判断需求是否满足

  • text或者[ expression ],不支持正则表达式
  • [[ expression ]]
    支持扩展正则表达式与通配符
    变量加双引号,为了避免空值造成语法错误,通配符正则表达式不要加双引号,
    比对用“=~”(匹配的意思),支持扩展正则表达式
    判断相等使用‘==’,支持通配符,支持字符串和整数

    例:判断用户输入的是否为ip
     #!/bin/bash
     read -p 'please input the IP: ip
     [[ "$ip" =~ ^(([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5]) ]] && echo "true" || echo "false"
    ps:[[]]括号中的表达式两边要加空格
        ip地址判断式解释:整体编组带'.'出现3次,结尾再加一组0-255
    

1.7.1 判断大小

选项 含义
-eq 等于,仅支持整数
-ne 不等
-lt 小于
-le 小于等于
-gt 大于
-ge 大于等于
    例:判断centos版本,根据版本使用响应命令启动网络
        #!/bin/bash                   <==脚本行首
        version=`grep -Eo '[[:digit:]]+' /etc/centos-release |head -n1 `        <==取出版本号
        [ $version -eq 6 ] && `service network restart`                 <==判断版本
        [ $version -eq 7 ] && `systemctl restart network`

1.7.2 判断文件属性

  • 判断文件类型,判断的是指向的实际文件,而不是软链接
    先通过-L判断是否为软链接
选项 含义
-b 是否存在且为块设备文件
-c 是否存在且为字符设备文件
-d 是否存在且为目录文件
-f 是否存在且为普通文件
-h 是否存在且为符号链接文件
-p 是否存在且为字命名管道文件
-S 是否存在且为套接字文件
-L 是否为软链接文件
-r 是否存在且可读
-w 是否存在且可写
-x 是否存在且可执行
-u 是否存在且拥有suid权限
-g 是否存在且拥有sgid权限
-k 是否存在且拥有sticky权限
-s 是否存在且为非空文件
-nt (newer than)判断file1是否比file2新
-ot (older than)判断file1是否比file2旧
-ef file1是否为file2的硬链接
  • 多重条件判断
选项 含义
-a 两个条件同时成立
-o 两个条件任何一个成立
取反状态
例1:判断文件是否为普通文件并且具有写权限,就去掉文件写权限
    [ -f "$file" -a -w  "$file"  ] &&chmod -w fild    
例2:判断文件是否为普通文件或者具有写权限,就去掉文件写权限。
    [ -f "$file" -o -w  "$file"  ] &&chmod -w fild
例3:利用非(!)表示如果文件不具有执行权限,就加上执行权限
    [ !  -x  "$file" ]&&	chmod  +x  $file

1.8 bash的配置文件

修改配置文件,理论上放哪里都可以执行,推荐有侧重的分类放置,方便查找。

按生效范围划分,存在两类:

  • 全局配置
    /etc/profile
    /etc.profile.d/*.sh
    /etc/bashrc
  • 个人配置
    ~/.bash_profile
    ~/.bashrc

按功能划分

  • profile启动程序和环境变量
  • bashrc别名、函数和本地变量

bash退出的配置文件

  • 退出后执行的配置文件,常用于创建自动备份 清除临时文件,将更改保存在~/.bash_logout文件中。

1.8.1 配置文件生效及顺序

在登录Linux时,用户ID就有了一个默认的shell,也就是登录shell。如果这个shell是bash,那么它就会在控制系统前执行几个脚本,然后按顺序执行。等用户退出是,如果主目录中有~/.bash_logout脚本,bash就会执行。

  • 配置文件的生效
    1、重新启动shell
    2、source

  • 交互式登录
    1、直接通过终端输入账号密码登录
    2、使用su -UserName切换账户

    执行顺序:
    /etc/profile ==> /etc.profile.d/*.sh ==> ~/.bash_profile ==> ~/.bashrc ==> /etc/bashrc
    
  • 非交互式登录
    1、su UserName
    2、图形界面下打开终端
    3、执行脚本
    4、任何其他的bash实例

    执行顺序:  
    ~/.bashrc ==> /etc/profile ==> /etc.profile.d/*.sh
    

1.9 [ ]、()与{}使用说明

  • [ ]用于逻辑判断,不能执行命令
  • ()与{}可以执行组合命令

     {}最后一个命令也要加";",前后要加空格,不开子进程影响当前环境。
     ()最后一个命令可以不加";",前后可以不加空格,开子进程不影响当前环境
    

2. 定制和使用shell环境

2.1 定义

以一组文字或符号等,来取代一些设定或者是一串 保留的数据

2.2 变量命名规则

    1、不能使用程序中的保留字,比如if  for   do  done这些内部命令的关键字
    2、可以使用数字、字母和下划线,且不能以数字开头
    3、见名知意,不要用汉字
    4、统一命名规则:驼峰命名法 userName 将两个单词用大写字母隔开,或者user_name
    5、变量内容若有空格使用“”或‘’将内容括起来。单引号视变量内容为字符串,双引号会保留特殊字符如$等的原本特性,使用\将特殊符号转译也行。
    6、变量内容需要调用其他指令信息时,使用反向单引号[`指令`]或[$(指令)]
    7、若变量为扩增变量内容时,则可用“$变量”或${变量}累加内容。[PATH="$PATH":/home/bin]
    8、若变量需要在其他程序执行,则需要以export来使变量变成环境变量

2.3 变量的种类

     局部变量:生效范围为当前窗口,shell当前进程中,对当前shell之外其他脚本无效,不能传给子进程及上级进程。
     环境变量:可以给当前shell用,也可以传递给子进程,不能传递给父进程。
     位置变量:在运行脚本时调用通过命令行传递给脚本的参数            
     只读变量:不可删除的变量,可用命令readonly定义

2.3.1 位置变量用法

    $1、$2...:对应第1、第2...参数,shift[n]换位置
    $0:命令本身
    $*:传递给脚本的所有参数,视为一个整体
    $@:传递给脚本的所有参数,每个参数为独立字符串
       $@和$*在被双引号抱起来的时候才会有差异
    $#:传递给脚本的参数个数   
    set-- 清空所有位置变量

    例1:根据位置变量介绍,编写一个测试脚本lication.sh,执行脚本后面跟10个参数,观察执行结果
        #!/bin/bash              <==脚本第一行
        echo 1st arg is $1       <==位置变量$1
        echo 2st arg is $2
        echo 3st arg is $3
        echo 10st arg is $10     <==位置变量$10,这么写会有问题。
        echo all args are $@
        echo all args are $*
        echo the args num is $#
        echo the scriptname is $0

    [root@V9centos7 /data]#./location.sh a b c d e f g h i j
        1st arg is a      <==对应变量$1
        2st arg is b
        3st arg is c
        10st arg is a0    <==对应变量10,但是系统会认为是1和0,所以显示为a0,这里要在脚本中该为${10}
        all args are a b c d e f g h i j 
        all args are a b c d e f g h i j 
        the args num is 10
        the scriptname is ./location.sh

命令:shift [n]
将位置变量向左移动1个参数, 1 1 就 会 去 掉 , 执 行 2,再执行shift去掉 2 2 , 执 行 3. shift 2一次过两个。

    应用:将来编脚本用,处理完就shift,然后就执行下一个,让执行的对象始终放置第一位
    例 2:将例1的脚本加上shift命令,观察输出结果
        #!/bin/bash
        echo all args are $@
        echo 1st arg is $1
        shift 2            <==一次移动2个参数
        echo all args are $@
        echo 1st arg is $1
        shift 2
        echo all args are $*
        echo 3st arg is $3

    [root@V9centos7 /data]#./location.sh a b c d e f g h i j 
        all args are a b c d e f g h i j
        1st arg is a
        all args are c d e f g h i j
        1st arg is c     <==移动2个参数,c变成第一个
        all args are e f g h i j
        3st arg is g

2.4 变量赋值

变量=值(会覆盖之前的值),值也可以引用命令,文件,变量
PS:在bash中没有设定的变量去echo,会显示空值。

    例:变量赋值后,被另一个变量调用,此时再将第一个变量重新赋值,调用它的那个变量仍然显示之前变量。说明变量赋值会有缓冲期,将不使用的变量值当做垃圾文件暂存。

    title=’ceo’
    name=$title            赋值变量记得加$
    echo $name => ceo         
    title=’boss’           将title重新赋值
    echo $name => ceo     name仍然显示ceo

2.5 引用变量

利用命令echo读出变量,只需要在变量前加$

2.6 变量常用命令

    echo $$              查看当前在那个进程中
    echo $PPID           查看父进程
    pastree  -p          看进程数
    set                  可以查看当前所有的变量和函数   
    declare  -x          看环境变量   
    declare –x  name=xx  定义环境变量
    export               看环境变量,可以将局部变量定义为环境变量
    unset                删除变量  只读变量不能删
    readonly             查看所有只读变量    加上变量等式定义为只读变量
    declare-r            看所有只读变量
    env                  环境变量与常见环境变量说明

2.7 变量内容的删除、取代

变量设定方式 说明
${变量#关键词} 若变量内容从头开始的数据符合关键词,则将符合的最短数据删除
${变量##关键词} 若变量内容从头开始的数据符合关键词,则将符合的最长数据删除
${变量%关键词} 若变量内容从尾向首的数据符合关键词,则将符合的最短数据删除
${变量%%关键词} 若变量内容从尾向首的数据符合关键词,则将符合的最长数据删除
${变量/旧字符串/新字符串} 若变量符合旧字符串,则第一个旧字符串会被新的取代
${变量//旧字符串/新字符串} 若变量符合旧字符串,则全部旧字符串会被新的取代
    例:将root的MAIL变量分别只留基名和目录名,再将root替换成大写
    [root@V9centos7 /data]#echo ${MAIL##*/}
    root     <==双#号匹配最长的字符串到/
    [root@V9centos7 /data]#echo ${MAIL%/*}
    /var/spool/mail    <==双%号匹配从后向前最短的字符串到/
    [root@V9centos7 /data]#echo ${MAIL/root/ROOT}
    /var/spool/mail/ROOT   

2.8 变量内容替换

变量设定方式 变量未设定 变量为空字符 变量已设定
${变量1-变量2} 变量2 空字符 变量1
${变量1:-变量2} 变量2 变量2 变量1
${变量1=变量2} 变量2 空字符 变量1
${变量1:=变量2} 变量2 变量2 变量1
${变量1+变量2} 未设定 变量2 变量2
${变量1:+变量2} 未设定 空字符 变量2
${变量1?提示语} 打印错误输出 空字符 变量1
${变量1:?提示语} 打印错误输出 打印错误输出 变量1

PS:如果只想知道,变量1是否存在,不存在就打印提示语,就可以用?判断。

3. 相关命令

3.1 命令read

应用:把输入值分配给一个或多个shell变量,不加选项直接加变量,就是给这个变量赋值

    格式:read [选项] [变量]
    选项:-p  指定要提示的内容
         -s   静默输入,一般用于密码
         -t   可以接等待的秒数
         -n # 指输入的字符长度#
         -d   ‘字符’输入结束符

    例1:可以对变量赋值,可以对多个
    [root@V9centos7 ~]#read name date path<<"v9 20180810 /var/bin/data"
    [root@V9centos7 ~]#echo $name
    v9
    [root@V9centos7 ~]#echo $date
    20180810
    [root@V9centos7 ~]#echo $path
    /var/bin/data

3.2 命令declare

应用:宣告变量的类型

    格式:declare  [选项]  [变量]
    选项:-a  将变量定义为数组(array)类型
         -i   将变量定义为整数数字(integer)类型
         -x   同export,定义为环境变量
         -r   将变量定义只读类型,需要注销再登录才能复原
         -p   单独列出变量类型

3.3 命令echo

  • 应用
    用于在shell中打印shell变量的值,或者直接输出指定的字符串
  • 格式
    echo [ -neE] [参数]
  • 选项:
    -E:(默认)不支持\解释功能
    -n:不自动换行
    -e:若字符串中出现以下字符,则特别加以处理,而不会当成一般文字输出

    • \a 发出警告声;
    • \b 删除前一个字符;
    • \c 最后不加上换行符号;
    • \f 换行但光标仍旧停留在原来的位置;
    • \n 换行且光标移至行首;
    • \r 光标移至行首,但不换行;
    • \t 插入tab;
    • \v 与\f相同;
    • \ 插入\字符;
    • \nnn 插入nnn(八进制)所代表的ASCII字符;
  • 参数
    变量:指定要打印的变量

  • 示例

    • 1.输出www.baidu.com,以蓝色,闪烁格式

      1. 前景色
        重置=0,黑色=30,红色=31,绿色=32,黄色=33,蓝色=34,洋红=35,青色=36,白色=37
      2. 背景色
        重置=0,黑色=40,红色=41,绿色=42,黄色=43,蓝色=44,洋红=45,青色=46,白色=47
      3. 功能参数
        0 关闭所有属性、1 设置高亮度(加粗)、4 下划线、5 闪烁、7 反显、8 消隐
echo -e "\033[34;5mwww.baidu.com\e[0m"
  • 2.输入ok!a sunday,取消字母a将sunday换行显示
echo -e  "ok! a\b \nsunday"
ok!  
sunday

你可能感兴趣的:(Linux学习12-shell环境与脚本基础)