关于 shell脚本编程第一篇

                                               shell脚本编程(1)

脚本的基本格式:

              程序:指令+数据

程序编程风格分为两种:

                    过程式:以指令为中心,数据服务于指令

                    对象式:以数据为中心,指令服务于数据

过程式编程有以下几个特点:

                        顺序执行

                        循环执行

                        选择执行

shell编程:

          过程式、解释执行

          编程语言的基本结构

          数据存储:变量、组数

          表达式:a+b

          语句: if                        

shell程序:是一个过程式的解释器,提供了编程能力,解释执行

程序的执行过程:先把源码程序翻译成机器语言(生成可执行的文件),然后解释执行。

对于过程式编程而言,把一行源码程序翻译成机器语言,然后执行,在翻译下一行的源码程序为机器语言,然后再次执行

对于计算机,只能识别的是二进制文件

编程语言:

       低级:

           汇编语言

       高级:

           编译过程:高级语言>编译器>目标代码 如:java ,C          

           解释过程:高级语言>解释器>机器代码 如: shell,perl,python

           

shell 脚本其实就是以一系列命令组合起来的文本文件,这些命令组合起来完成一个或者一项功能。

 也可以这样理解 shell脚本是包含好一些命令或声明,并符合一定格式的文本文件            

格式要求:shell程序开头的环境指定,我们称之为shebang机制

        #!/bin/bash

        #!/usr/bin/python

        #!/usr/bin/perl

        各种命令组合在一起,形成一个脚本

shell脚本的用途有:

                 自动化常用命令

                 执行系统管理和故障排除

                 创建简单的应用程序

                 处理文本或文件

     

创建shell脚本:

             使用编辑器来创建文本文件

             第一行必须包括shell声明序列:#!  #!/bin/bash

             添加注释信息 以#开头     

     

运行脚本:

        给予执行权限,通过具体的文件路径制定文件执行

        直接运行解释器,将脚本作为解释器程序的参数运行

脚本调式:

        bash -n /path/to/some_script     检查脚本中是否语法错误

        bash -x /path/to/some_script     调试执行

       

  

shell脚本格式示例

#!/bin/bash/        开头格式

#                   注释信息

# Author: root      

# date: 20160812-08:12:08

# Vervion: 0.0.1

# Description:

# Synopsis:

   echo "信息内容"

关于变量:

         什么是变量:命名的内存空间

                     数据存储方式

变量作用类型:

            作用:

                数据存储格式

                参与运算

                表示的数据范围

            类型 : 

                 字符

                 数值: 整型,浮点型

                     

      

变量类型分为两类:

强类型:定义变量是必须指定类型、参与运算必须符合类型要求;调用未声明变量会产生错误

弱类型:无需指定类型,默认均为字符型;参与运算会自动进行隐式类型转换;变量无须是想定义可直接调用

变量命名法则:

            不能使用程序中的保留字:例如if,for等

            只能使用数字、字母及下划线,且不能以数字开头

            要做到看到变量名称就知道是什么意思;见名知意

            统一命名法则:驼峰命名法   

            大驼峰:两个单词开头字母为大写

            小驼峰:两个单词,第一个开头为小写,第二个开头为大写

bash中变量的种类:

根据变量的生效范围等标准可分为:   

                              本地变量:生效范围为当前shell进程;对当前shell之外的其他shell进程包括当前shell的子shell进程均无效;简单来说,本地变量,只能对本地使用

                              环境变量:生肖范围为当前shell进程以及子进程。

                              局部变量:生效范围为当前shelll进程中某代码片段(通常指的是函数)

                              位置变量:$1,$2,$3,….表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数

                              特殊变量:

                                       $?  上个命令是否执行成功

                                       $0  表示命令本身

                                       $#  传递给脚本参数的个数

                                       $*  传递给脚本的所有参数

                                       $@  引用传递给脚本的所有参数

                                       pstree   查看树形结构的进程        

本地变量: 

         变量赋值: name='value' (值) 值可以引用         

                  1  可以是直接字符串 例如 name="root"

                  2  变量引用   例如 name="$username"

                  3  命令引用   例如 name=`命令`,name=$(命令) 

         变量引用:$name,${name}

                  "" 弱引用,其中的变量引用会被替换成变量值

                  '' 强引用, 其中的便碧昂引用不会被替换变量值,而且保持原字符串

                  显示已经定义的所有变量:set

                  销毁变量:unset namme

练习

1编写脚本/root/bin/systeminfo.sh,显示当前主机系统信息,包括主机名,IPV4地址操作系统版本,内核本本,CPU型号,内存大小,硬盘大小

~]# vim systeminfo.sh

#!/bin/bash

#

ip=`ifconfig | grep 'inet\>' | grep -v '127.0.0.1' | tr -s ' ' | cut -d' ' -f3`

cpu=`lscpu | grep -i "model name:"`

neicun=`free -h |sed -n '2p' |tr -s ' ' | cut -d' ' -f2`

cipan=`fdisk -l | sed -n '2p' | sed -r 's/.*[[:space:]]([0-]9.*M).*/\1/g'`

echo 'hostname:'`hostname`

echo 'hostip:'$ip

echo 'OS version:'`cat /etc/redhat-release`

echo 'neihe:'`uname -r`

echo 'cpu:'$cpu

echo 'neicun:'$neicun

echo 'cipan:'$cipan

保存退出,chmod +x systeminfo.sh 加上执行权限,可直接运行

2编写脚本/root/bin/backup.sh,可实现将/etc/目录备份到/root/etcYYYY-mm-dd中

~]# vim backup.sh

#!/bin/bash

backdir="/root/etc$(date +%F)"

cp -a /etc/. $backdir && echo "comon $backdir stop." 

保存退出,chmod +x backup.sh 加上执行权限可直接运行

3 编写脚本/root/bin/disk.sh,显示当前硬盘分区 中空间利用最大的值

#!/bin/bash

#

cipanname=`df |grep '/dev/sd' | tr -s ' '|sort -nr -t' ' -k5|cut -d' ' -f1`

shiyonglv=`df |grep '/dev/sd' | tr -s ' '|sort -nr -t' ' -k5|cut -d' ' -f5`

echo $cipanname

echo $shiyonglv

保存退出,chmod +x disk.sh 加上执行权限可直接运行

4 编写脚本/root/bin/links.sh,显示正在连接本主机的每个远程主机的IPV4地址和连接数,并按连接输从大到小排序

#!/bin/bash

#

echo -e "lianjie: \n\tlianjieshu\tip"

netstat -nt |tr -s ' '|cut -d' ' -f5| tr -cs '0-9.' '\n'|egrep '([0-9]+.){3}[0-9]+'|sort|uniq -c|sort -nr|tr -s ' ' '\t'

环境变量;

        变量声明、赋值

        export name=值      输出 名称 值

        declare -x name=值  声明 选项 名称 值

变量引用: $name,${name}

显示所有的环境变量:

                  export

                  env

                  printenv

                  销毁 : unset name 

 bash中有许多内建的环境变量:PATH,SHELL,USRE,UID,HISTSIZE,HOME,PWD,OLDPWD,HISTFILE,PS1

  

只读变量:只能读,但不能修改和删除

         readonly name     只读

         declare -r name   声明

位置变量:在脚本代码中调用通过命令传递给脚本的参数

             $1,$2,$3…   对应调用第1.第2第3等参数

             $0  表示命令本身

             $*  传递给脚本的所有参数,全部参数何为一个字符串

             $@  引用传递给脚本的所有参数,每个参数为独立字符串

             $#  传递给脚本参数的个数,

             $@ $* 只有在被双引号包起来时候才会有差异

         

bash中的算数运算:help let

                 +,-,*,/,% 取模式(取值)**(乘方)

                实现算数运算:

                1 let var=算数表达式

                2 var =$[算数表达式]      ]# number=$[2**3]     ~]# echo $number

                3 var =$((算数表达式))   ~]# number=$((2**3))   ~]# echo $number

                4 var =$(expr表达式 arg1 arg2 arg3…) 如A=$(expr $B \* $C)

                5 declare -i var = 数值

                6 echo  '算数表达式' | bc

                注意:*乘法符号有些场景中需要转义

                bash有内建的随机数生成器:$RANDOM(1-32767)

                echo $[$RANDOM%50]  表示0-49之间的随机数

                echo $[$RANDOM%50+2] 表示1-50之间的随机数

增强型赋值:

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

          使用方法:let var+=5    var值就是5

          自增,自减

          let var+=5      var=5 

          let var++       在原有的数值上面加上1 比如原先设定的是5执行一次let var++就相当于加上数值1      

          let var-=1      在原有的数值上面减去1个数值

          let var–       在原有的数值上面减去1个数值

练习

5 写一个脚本/root/bin/sumid.sh,计算/etc/passwd文件中的第10个用户和第20个用户之和

~]# vim sumdi.sh

#!/bin/bash

#

uid1=`sed -n '10p' /etc/passwd | cut -d: -f3`

uid2=`sed -n '20p' /etc/passwd | cut -d: -f3`

let sumid=$uid1+$uid2

echo -e "The 10 user ID is $uid1 ;\nthe 20 user ID is $uid2 ;\n\tthe sum of two users ID is $sumid ."

  

保存退出 chmod +x sumid.sh 加上执行权限

6写一个脚本/root/bin/sumfile.sh,统计/etc, /var, /usr目录中共有多少个一级子目录和文件

~]# vim sumfile.sh

#!/bin/bash

#

file1=`ls -A /etc | wc -l`

file2=`ls -A /var | wc -l`

file3=`ls -A /usr | wc -l`

let sumfile=$file1+$file2+$file3

echo "$sumfile"

逻辑运算

在shell编程当中支持一些逻辑运算:    true1 真为1 false0 假为0

                               与运算:

                                     1与1=1  1&&1=1    1和任何数相与 是原值  1和1相与为原来的值1

                                     1与0=0  1&&0=0    0和任何数相与 是0     1和0相与为原来的值0

                                     0与1=0  0&&1=0    0和1相与 等0

                                     0与0=0  0&&0=0

                               或运算:

                                     1或1=1   1||1=1    只要有一个是真结果就为真,       

                                     1或0=1   1||0=1           只要两个都是假结果就为假,

                                     0或1=1   0||1=1       

                                     0或0=0   0||0=0

                               非运算:

                                     !1=0     非真 则为假

                                     !0=1     非假 则为真

短路运算:

        短路与:

               第一个为0, 结果必定为0             命令1与命令2

               第一个为1,第二个必须要参与运算      假0    假0   如果命令1成功将执行2

                                                           如果命令1失败,将不执行命令2 

       短路或:

              第一个为1,结果必定为1              命令1命令2    如果命令1执行成功将不执行命令2

              第一个为0,第二个必须要参与运算      真1   真1    如果命令1执行不能功执行命令2

         异或:^

             异或的两个值,相同为假,不同为真        ‘异性相吸 ,同性为假’  两个值相同为假,不相同则为真

      

两种聚集命令的方法:

                  复合式:date; who| wc -l

                          命令会一个接一个地运行   顺序执行,从左往右生效

         

                 子shell:(date;who | wc -l)>> /tmp/tarce

                          可以执行单个体命令

                          (date; who)| wc -l可以先执行括号里面的命令

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

                 0  表示成功 ,1-255 代表失败

                 $? 变量保存最近的命令退出状态

                    例如 echo $?  可以查看上一条命令是否成功或失败

自定义退出状态码: exit

                 注意:

                     1 脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字

                     2 如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

      

条件测试:

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

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

        若真,返回的是0

        若假,返回的是1  

        测试命令:

                test 表达式          $w = $r

                test [表达式]  ]   [ $w = $r ]

                test [[表达式]] ] [[ $w = $r ]]

        注意:表达式 前后必须有空白字符

条件性的执行操作符:

 根据退出状态而定,命令可以有条件地运行

命令1 && 命令2  短路与, 命令1成功,将执行命令2    ,如果命令1失败,将不执行命令2

命令1 || 命令2  短路或, 命令1成功,将不执行命令2 ,如果命令1失败,将执行命令2

bash 的测试类型

       数值测试:

              -gt  是否大于           

              -ge  是否大于等于

              -eq  是否等于

              -ne  是否不等于

              -lt  是否小于

              -le  是否小于等于

       字符串测试:

               ==  是否等于

               >   是否大于

               <   是否小于

               !=   是否不等于

               =~    左侧字符串是否能够被右侧的表达式所匹配

                  注意;此表达式一般用于[[ ]]

               -z 字符串      字符串是否为空,空为真、不空为假

               -n 字符串      字符串是否不空, 不空为真,空为假

               注意:用于字符串比较时的用到的操作数都应该使用引号

文件测试  :

        存在性测试:

                 -a file 同-e

                 -e file  文件存在性测试,存在为真,否者为假;

存在性和类别测试:

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

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

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

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

              -h file  或者 -L file  存在且为符号链接文件

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

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

  文件权限测试:

            -r file 是否存在并且可读

            -w file 是否存在并且可写

            -x file 是否存在并且可执行

  文件特殊权限测试:

            -g file 是否存在且拥有sgid 的权限

            -u file 是否存在切拥有suid 的权限

            -k file 是否存在且拥有sticky的权限

   文件大小测试:

            -s file 是否存在且非空

    文件是否打开:                          

            -t fd     文件描述符是否已经打开并且与某终端相关

            -N file   文件上一次杜宇之后是否被修改过            

            -O file   当前有效用户是否为文件属主

            -G file   当前有效用户是否为文件属组

    双目测试::

      file1 -ef file2       文件1和文件2 是否指定向同一个设备上的相同inode 是否为同一个文件

      file1 -nt file2       文件1是否新于文件2

      file1 -ot file2       文件1是否旧与文件2              

 组合测试条件: 

       第一种方式: 

         命令1 && 命令2  并且

         命令1 || 命令2  或者

         !命令     非

         例如 [ -e file ] && [ -r file ]                

        第二种方式:

           表达式1 -a 表达式2  并且

           表达式1 -o 表达式2  或者

           !表达式   非

                  

                 

练习

编写脚本/root/bin/nologin.sh和login.sh,实现禁止和允许普通用户登录系统。

#!/bin/bash

#

[ -f /etc/nologin ] && echo "user disable login already" || (touch /etc/nologin; echo user disable login )                

   禁止普通用户登录              

#!/bin/bash 

#

[ -f /etc/nologin ] && (rm -f /etc/nologin;echo user enable login) ||  echo user disable login already              

   允许普通用户登录             

                 

计算1+2+3+…+100的值                 

#!/bin/bash

#

shuzi=`echo {1..100}|tr ' ' '+'| bc`

echo $shuzi                 

                 

                 

原创文章,作者:小马哥,如若转载,请注明出处:http://www.178linux.com/35714

评论列表(1条)

  • 马哥教育
    马哥教育 2016-08-16 16:56

    总结的很好,很细致,结构清晰,注意理论与实践相结合。

联系我们

400-080-6560

在线咨询

工作时间:周一至周五,9:30-18:30,节假日同时也值班

QR code