Linux自学笔记——shell脚本编程

  1. 云栖社区>
  2. 博客>
  3. 正文

Linux自学笔记——shell脚本编程

技术小阿哥 2017-11-27 11:43:00 浏览1468
展开阅读全文

脚本文件格式:

   第一行,顶格:#!/bin/bash

   注释信息:#

   代码注释:

缩进,适度添加空白行

语言:编程语法格式,库,算法和数据结构;

编程思想:

   问题空间 à解空间

变量:

   局部变量

   本地变量

   环境变量

   位置参数变量

   特殊变量

数据类型:字符型、数值型

   弱类型:字符型;

Bash中的算术运算:

+,-,*,/,%,**

实现算术运算:

1)let var=算术表达式;

2)var=$[算术表达式]

3)var=$((算术表达式))

4)var=$(expr arg1 arg2 arg3…)

 

乘法符号在有些场景中需要转义;

Bash有內建的随机数生成器;$RANDOM

增强型赋值:

+=,-=,*=,/=,%=

   let varOPERvalue

      例如:let count+=1

自增,自减:

   let var+=1

      let var++

   let var-=1

      let var—

练习1:写一个脚本,计算/etc/passwd文件的第10个用户和第20个用户的ID之和;

   wKiom1nIneKCpBRXAABD7JlHjxo414.png-wh_50

练习2:写一个脚本,传递两个文件路径作为参数脚本,计算这两个文件中所有空白行之和;

   wKioL1nInbCBjYNxAABDTknh1OI480.png-wh_50

条件测试:

判断某需求是否满足,需要由测试机制来实现;

 

如何编写测试表达式以实现所需的测试:

1)执行命令,并利用命令状态返回值来判断;

0:成功;

1-255:失败;

2)专用的测试表达式需要由测试命令辅助完成测试过程;

测试命令:

   test EXPRESSION

   [ EXPRESSION ]

   ` EXPRESSION `

   NOTE:expression前后必须有空白字符;

Bash的测试类型:

   数值测试:数值比较

      -gt:是否大于;

      -ge:是否大于等于;

      -eq:是否等于;

      -ne:是否不等于;

      -lt;是否小于;

      -le:是否小于等于;

   字符串测试:

      ==:是否等于;

      >:是否大于

      <:是否小于

      !=:是否不等于;

      =~:左侧字符串是否能够被右侧的PATTERN所匹配;

      Note:此表达式一般用于[[]]中;

      -z “string”:测试字符串是否为空,空则真,不空则为假;

      -n “string”:测试字符串是否为不空,不空则为真,空则为假;

      Note

1)用于字符串比较时的用到的操作数都应该使用引号;

      2)要使用[[]];

   文件测试:

      存在性测试:

        -a FILE

        -e FILE

        文件的存在性测试,存在则为真,否则则为假;

      存在性及类型测试:

        -b file:是否存在并且为块设备文件;

        -c file:是否存在并且为字符设备文件;

        -d file:是否存在并且为目录文件;

        -f file:是否存在并且为普通文件;

        -h file 或 –L file:是否存在并且为符号链接文件;

        -p file:是否存在并且为命名管道文件;

        -S file:是否存在并且为套接字文件;

      文件权限测试:

        -r file:是否存在并且对当前用户可读;

        -w file:是否存在并且对当前用户可写;

        -x file:是否存在并且对当前用户可执行;

      特殊权限测试:

        -u file:是否存在并且拥有suid权限;

        -g file:是否存在并且拥有sgid权限;

        -k file:是否存在并且拥有sticky权限;

      文件是否有内容:

        -s file:是否有内容;

      时间戳:

        -N file:文件自从上一次读操作后是否被修改过;

      从属关系测试:

        -O file:当前用户是否为文件的属主;

        -G file:当前用户是否为文件的属组;

      双目测试;

        File1 –ef file2:file1与file2是否指向同一个文件系统的相同inode的硬连接;

        File1 –nt file2:file1是否新于file2;

        File1 –ot file2:file1是否旧于file2;

   组合条件测试:

      逻辑运算:

      方式一:

        COMMAND1 && COMMAND2

        COMMAND1 || COMMAND2

        ! COMMAND

        [ -O FILE ] && [ -r file ]

      方式二:

        EXPRESSION1 –a EXPRESSION2

        EXPRESSION1 –o EXPRESSION2

        ! EXPRESSION

         [ -O FILE –a –x FILE ]

练习:将当前主机名称保存至hostName变量中,如果主机名为空,或者为localhost.localdomain,则将其设置为www.claude666.com;

    wKioL1nInb_zo9tKAABD8ldLvD8483.png-wh_50

脚本的状态返回值:

   默认是脚本中执行的最后一条件命令的状态返回值;

   自定义状态退出状态码:

      exit [n]:n为自己指定的状态码;

     note:shell进程遇到exit时,即会终止,因此,整个脚本执行即为结束;

 

向脚本传递参数:

位置参数变量

myscript.sh  argu1 argu2

引用方式:

    $1,  $2, ..., ${10}, ${11}, ...

轮替:

    Shift [n]:位置参数轮替

练习:写一脚本,通过命令传递两个文本文件路径给脚本,计算其空白行数之和;

   wKiom1nIngXzJcbbAABEpk-QXPo936.png-wh_50

 

过程式编程语言的代码执行顺序;

   顺序执行:逐条执行;

   选择执行;

      代码有一个分支;条件满足时才会执行;

      两个或以上的分支:只会执行其中一个满足条件的分支;

   循环执行;

      代码片段(循环体)要执行0、1或多个来回;

   选择执行:

      单分支的if语句:

        if 测试条件;then

           代码分支

        fi

      双分支的if语句:

        if 测试条件;then

           条件为真时执行的分支

        else

           条件为假时执行的分支

        fi

      多分支的if语句

        if  CONDITION1; then

           条件1为真分支

        elif  CONDITION2; then

           条件2为真分支

        elif  CONDITION3; then

           条件3为真分支

        ...

        elif  CONDITIONn; then

           条件n为真分支

        else

           所有条件均不满足时的分支

        Fi

      Note:即便多个条件同时满足,分支只会执行其中的一个,首先测试为“真”

示例1:脚本参数传递一个问文件路径给脚本,判断此文件的类型;

   wKiom1nIng-BXsYdAACFTQHVBBU084.png-wh_50

练习:写一个脚本

1)传递一个参数给脚本,此参数为用户名;

2)根据其id号来判断用户类型;

0:管理员

1-999:系统用户

1000+:普通用户

   wKioL1nInd2w1fJyAABiqZED0Lc333.png-wh_50

练习:写一个脚本

1)列出如下菜单给用户;

disk) show disks info;

mem) show memory info;

cpu) show cpu info;

*) exit

  2)提示用户给出自己的选择,而后显示对应其选择的相应系统信息;

   wKiom1nInjTRqunuAAAuj9Vi3ok948.png-wh_50

示例2:通过参数传递一个用户名给脚本,此用户不存在时,则添加之,如果存在,显示用户已存在;

   wKiom1nInj7gFErcAABYb4EyOls780.png-wh_50

练习1:通过命令行给定两个数字,输出其中较大的值;

   方法一:

   wKioL1nInguAojlfAABIIW7SGB4038.png-wh_50

   方法二:

   wKioL1nInhXinftxAABLg1PFhQY409.png-wh_50

练习2:通过命令行参数给定一个用户名,判断其ID号是偶数还是奇数;

   wKiom1nInliCkpA2AABUfhs5DLg711.png-wh_50

练习3:通过命令行参数给定两个文本文件名,如果某文件不存在,则结束脚本执行;都存在时返回每个文件的行数,并说明其中行数较多的文件;

   wKioL1nIniXAvJRlAACSnXZmulY371.png-wh_50

练习4:写一个脚本完成如下功能;

1)列出当前系统识别到的所有磁盘设备;

2)如磁盘数量为1,则显示其空间使用信息;否则,则显示左后一个磁盘上的空间信息;

wKiom1nInmqTXphFAACIyYAEfb8483.png-wh_50

在虚拟机再添加一块硬盘重新测试:

wKiom1nInnLTRqgvAAC1q7PWb4c149.png-wh_50

Bash脚本编程之用户交互:

   read [option]… [name …]

      -p 'PROMPT'后面跟提示信息,即在输入前打印处提示信息;

      -t TIMEOUT    后面跟秒数,意思为输入命令的等待秒数;

   bash -n /path/to/some_script

      检测脚本中的语法错误

   bash -x /path/to/some_script

      调试执行

示例1:输入一个磁盘分区,查看是否存在,存在则输出磁盘信息:

    wKioL1nInlPBswoLAACimU9ZNVg272.png-wh_50

示例2:添加用户及设置密码;

       wKioL1nInmDiLBwEAAA0p56tdEU596.png-wh_50

 

循环执行:将一段代码重复执行0、1或多次;

   进入条件:条件满足才进入循环;

   退出条件:每个循环都应该应该有退出条件,以有机会推出循环;

  

   Bash脚本:

      For循环

      While循环

      Until循环

for循环:

   两种格式;

1)遍历列表;

2)控制变量;

 

遍历列表:

for VARAIBLE in LIST;do

    循环体

done

进入条件:只要列表有元素,即可进入循环;

退出条件:列表中的元素遍历完成;

LIST的生成方式:

1)直接给出;

2)整数列表

a){start..end}

b)seq [start [incremtal] last]

   3)返回列表的命令;

   4)glob

   5)变量引用;$@,$*

练习:批量添加用户(for)

   wKiom1nInqeDy5zfAABo7QxG_wU581.png-wh_50

练习:求100以内所有正整数之和;

    wKiom1nInraiFQ26AAAYwpd-bw4465.png-wh_50

练习:判断/var/log目录下的每一个文件的内容类型

   wKiom1nInr_hFrpQAAA1KqbIfHc596.png-wh_50

练习:

1)分别求100以内所有偶数之和,以及所有奇数之和;

wKiom1nInsmQ3hxlAAArRLf8fFA739.png-wh_50

2)计算当前系统上的所有id之和;

wKioL1nInpmj23QgAAA0ItsRIJw062.png-wh_50

3)通过脚本参数传递目录给脚本,而后计算此目录下所有文本文件的行数之和;并说明此类文件的总数;

wKiom1nInt-hJWZ3AABAc2W3uu8390.png-wh_50

 

while循环:

   while CONDITION;do

      循环体

      循环控制变量修正表达式

   done

   进入条件:CONDITION测试为“真”

   退出条件:CONDITION测试为“假”

until循环:

   until CONDITION;do

      循环体

      循环控制变量修正表达式

   done

   进入条件:CONDITION测试为“假”

   退出条件:CONDITION测试为“真”

示例:求100以内所有正整数之和;

方法一:while循环

    wKioL1nInrjgWe-jAAAbP_-QRns889.png-wh_50

方法二:until循环;

    wKiom1nInv-wEoLPAAAlLT58mW4602.png-wh_50

练习:分别用for,while,until实现

1.分别求100以内所有偶数之和,100以内所有奇数之和;

方法一:for循环

wKiom1nInyeBC5_sAAA6Dvb42PY630.png-wh_50

方法二:while循环

wKiom1nInzKRAA2nAABD1-pAvok616.png-wh_50

方法三:until循环

wKioL1nInwDywrxvAABFHGIF4oE258.png-wh_50

2.创建10个用户,user101-user110;密码同用户名;

方法一:for循环

wKioL1nInwuxMNDXAAAhASkYZM8761.png-wh_50

方法二:while循环

wKiom1nIn0-zwgcbAAAmYmIlvFM761.png-wh_50

方法三:until循环

wKioL1nInyPiqVQ_AAAnGcvOVGM412.png-wh_50

3.打印九九乘法表;

方法一:for循环

wKiom1nIn2nB9DGwAABETW_f_B0073.png-wh_50

方法二:while循环

wKioL1nInzbTCi2BAABIn5XyJWs971.png-wh_50

方法三:until循环

wKiom1nIn3yylch6AABR-J2AcMs080.png-wh_50

4.打印逆序的九九乘法表;

方法一:for循环

wKioL1nIn5bSU7ggAABBf9FhZYs452.png-wh_50

方法二:while循环

wKiom1nIn9-Cnq9FAABMsoIqqug463.png-wh_50

方法三:until循环

wKiom1nIn_bQEmxpAABG6PebKCY444.png-wh_50

 

循环控制语句:

continue:提前结束本轮循环,而直接进入下一轮循环判断;

   while CONDITION  ;do

      CMD1

      …

      if CONDITION2;then

        continue

      fi

      CMDn

      …

   done

示例:求100以内所有偶数之和:

        wKiom1nIpc2hMSvrAAAiy2vrokM192.png-wh_50

 

Break:提前跳出循环

   While CONDITION1;do

      CMD1

      …

      if CONDITION2;then

        break

      fi

   done

 

创建死循环:

   while true;do

      循环体

   done

   退出方式;某个测试条件满足时,让循环执行break命令;

示例:求100以内所有奇数之和;

        wKioL1nIpZ_SUL0DAAAfgZQdDjE884.png-wh_50

 

sleep命令:

   delay for a specified amount of time

   sleep number

练习:每隔3秒到系统上获取已经登录的用户的用户信息;其中,如果cladue用户登录系统,则记录于日志中,并退出;

    wKiom1nIpemSZ8n9AAAiC-oKFfw580.png-wh_50

While循环的特殊用法(遍历文件的行)

   While read VARIABLE;do

      循环体

   done < /PATH/FROM/SOMEFILE

   一次读取/PATH/FROM/SOMEFILE文件中的每一行,且将基赋值给VARIABLE变量;

示例:找出ID号为偶数的用户,显示其用户名、ID以及默认shell;

        wKiom1nIpfbyVVwgAAAtZf286CM129.png-wh_50

 

for循环的特殊用法:

   for ((控制变量初始化;条件判断表达式;控制变量的修正语句));do

      循环体

   done

   控制变量初始化:仅在循环代码开始运行时执行一次;

   控制变量的修正语句:每轮循环结束会先进行控制变量修正运算,而后再做条件判断;

示例:求100以内所有正整数之和;    

    wKiom1nIpgTAwirrAAAhqoTY66M789.png-wh_50

示例;打印九九乘法表;

            wKioL1nIpdXCFlNbAAA9dW-pk_4221.png-wh_50

case语句:

case语句的语法格式:

   case $VARAIBLE in

   PAT1)

      分支1

      ;;

   PAT2)

      分支2

      ;;

   …

   *)

      分支n

      ;;

   esac

case支持的glob风格的通配符:

   *:任意长度的任意字符;

   ?:任意单个字符;

   []:范围内任意单个字符;

   a|b:a或b

 

示例1:显示一个菜单给用户;

cpu) display cpu information

mem) display memoryinformation

disk) display disksinformation

quit) quit

要求:(1) 提示用户给出自己的选择;

(2) 正确的选择则给出相应的信息;否则,则提示重新选择正确的选项;

        wKiom1nIph6gGG4HAABH9NJ4hQg305.png-wh_50

示例:写一个服务框架脚本:

$lockfile,值/var/lock/subsys/SCRIPT_NAME

1)接受参数start,stop,restart,status四个参数之一;

2)如果参数非此四者,则提示使用帮助后退出;

4)Start,则创建lockfile,并显示启动;stop,则删除lockfile,并显示停止;restart,则先删除此文件再创建文件,而后显示重启完成;status,如果lockfile存在,显示running,否则,显示stoped。

        wKioL1nIphvgBJXOAABtkNovkJ4217.png-wh_50

Note:第一行代码basename $0.获取脚本的名字。想对哪个服务管理,将脚本改成对应的名字即可;

 

函数:function

   过程式编程:代码重用

      模块化编程

      结构化编程

     

      把一段独立功能的代码当作一个整体,并为之一个名字;命名的代码段,此即为函数;

      Note:定义函数的代码段不会自动执行,在调用时执行;所谓调用函数在代码中给定函数名即可;

      函数名出现的任何位置,在代码执行时,都会被自动替换成函数代码;

语法一:

   function f_name {

函数体…

}

语法二:

   f_name() {

      …函数体…

}

函数的生命周期:每次被调用时创建,返回时终止;

   其状态返回结果为函数体中运行的最后一条命令的状态结果;

   自定义状态返回值,需要使用return

      return [0-255]

        0:成功

        1-255:失败

示例:给定一个用户名,取的用户的id号和默认shell;

        wKiom1nIpmKTGsXIAAAx3TFP_Qs755.png-wh_50

示例2:上述例子的服务脚本框架(用函数)

        wKioL1nIpjCjHcVMAAB80NnWi-Y819.png-wh_50

函数返回值:

   函数的执行结果返回值;

1)使用echo或print命令进行输出;

2)函数体中调用的命令的执行结果;

函数的退出状态码:

1)默认取决于函数体中执行的最后一条命令的退出状态码;

2)自定义:return

函数可以接受参数:

   传递参数给函数:

在函数体当中,可以使用$1,$2,…引用传递给函数的参数,还可以函数中使用$*或$@引用所有的参数,$#引用传递的参数的个数;

      在调用函数时,在函数名后面以空白符分隔给定参数列表即可,例如,testfunc arg1 arg2 arg3…

示例:添加10个用户,添加用户的功能使用函数实现,用户名作为参数传递给函数;

        wKioL1nIpj2TJ7eUAAA1TieDVoA268.png-wh_50

练习:写一个脚本,使用函数ping一个主机来测试主机的在线状态;主机地址通过参数传递给函数;

   主程序:测试192.168.19.129-192.168.19.139范围内主机的在线状态;

   wKioL1nIpkmjj23-AAA4TF2rAbk193.png-wh_50

练习:打印N*N乘法表;

   wKioL1nIplSgcH33AABsj6gtjeo713.png-wh_50

变量作用域:

   局部变量:作用域是函数的生命周期;在函数结束时被自动销毁;

      定义局部变量的方法:localVARIABLE=VALUE

   本地变量:作用域是运行脚本的shell进程的生命周期;因此,其作用范围为当前shell脚本程序文件;

示例程序:

   wKiom1nIppmy3G_rAAAkjDB0bow178.png-wh_50

函数递归:

   函数直接或间接调用自身:

示例:求10!

   wKioL1nIpmji4lrvAAAxDQ8dmtg710.png-wh_50



本文转自 claude_liu 51CTO博客,原文链接:http://blog.51cto.com/claude666/1968424,如需转载请自行联系原作者

网友评论

登录后评论
0/500
评论
技术小阿哥
+ 关注