精华内容
下载资源
问答
  • 概述shell是一个命令解释器,是一个程序/bin/bash,解释linux的命令,而shell脚本是一系列的命令组成的文件,想要熟练掌握shell脚本,唯有不断练习,接触各种各样的需求并用shell来实现才可以。需求利用case语句编写...

    概述

    shell是一个命令解释器,是一个程序/bin/bash,解释linux的命令,而shell脚本是一系列的命令组成的文件,想要熟练掌握shell脚本,唯有不断练习,接触各种各样的需求并用shell来实现才可以。


    需求

    利用case语句编写脚本,满足下列要求

    1.执行create时根据userfile和passfile建立用户

    2.执行delete时根据userfile删除用户


    1、脚本内容:

    # vim user_ctrl.sh#!/bin/bashread -p "Please input the operation (create or delete ): " OPERATION //输入你要执行的动作case $OPERATION in create) //第一种情况:create read -p "Please input the userfile : " USERFILE //提示输入文件 [ -e $USERFILE ] || { //判断是否存在 echo "$USERFILE is not exist " exit 1 } read -p "Please input the passwdfile : " PASSFILE [ -e $PASSFILE ] || { echo "$PASSFILE is not exist " exit 1 } USERLINE=`awk 'BEGIN{N=0}{N++}END{print N}' $USERFILE` //计算userfile文件行数 for LINE_NUM in `seq 1 $USERLINE` //利用循环建立 do USERNAME=`sed -n "${LINE_NUM}p" $USERFILE` //截取userfile文件第一行内容 PASSWORD=`sed -n "${LINE_NUM}p" $PASSFILE` //截取passfile文件第一行内容 useradd $USERNAME //建立用户 echo $PASSWORD | passwd --stdin $USERNAME done ;; delete) //第二种情况:delete read -p "Please input the userfile : " USERFILE [ -e $USERFILE ] || { echo "$USERFILE is not exist " exit 1 } USERLINE=`awk 'BEGIN{N=0}{N++}END{print N}' $USERFILE` for LINE_NUM in `seq 1 $USERLINE` do USERNAME=`sed -n "${LINE_NUM}p" $USERFILE` userdel -r $USERNAME done ;; *) //第三种情况:其余各种情况 echo Error! ;;esac
    13677e07df0a1035f2933982607d5ece.png

    2、执行:

    [root@localhost mnt]# cat userfile user1user2user3[root@localhost mnt]# cat passfile 123456789[root@localhost mnt]# sh user_ctrl.sh user Please input the operation (create or delete ): hello //输入错误动作Eorror![root@localhost mnt]# sh user_ctrl.sh user Please input the operation (create or delete ): createPlease input the userfile : user //输入错误文件user is not exist [root@localhost mnt]# sh user_ctrl.sh user Please input the operation (create or delete ): createPlease input the userfile : userfilePlease input the passwdfile : passfile //建立用户Changing password for user user1.passwd: all authentication tokens updated successfully.Changing password for user user2.passwd: all authentication tokens updated successfully.Changing password for user user3.passwd: all authentication tokens updated successfully.[root@localhost mnt]# sh user_ctrl.sh user Please input the operation (create or delete ): delete //删除用户Please input the userfile : userfile[root@localhost mnt]# id user1id: user1: no such user
    8419b2cb0a115c9cc3af6e14361e975d.png
    93efa4e068c8a0056b865e6b60d0dc5f.png

    关于shell脚本就介绍到这了,大家在看需求的时候建议自己先写一下,然后再对着改进,效果会好一点。后面小编会分享更多linux方面内容,感兴趣的朋友走一波关注哩~

    0cff8f83ccd107a200dcd00010591337.gif
    展开全文
  • 如何编写Shell脚本

    2019-06-06 17:19:00
    Shell 脚本(shell script),是一种为 shell 编写的脚本程序shell script是一种解释型语言,必须由解释器来执行这些脚本,执行时,解释器将脚本一行一行地转换为代码。 这个解释器就是Shell,它是一个用 C 语言...

    什么是shell脚本
    Shell 脚本(shell script),是一种为 shell 编写的脚本程序。shell script是一种解释型语言,必须由解释器来执行这些脚本,执行时,解释器将脚本一行一行地转换为代码。

    这个解释器就是Shell,它是一个用 C 语言编写的程序。常见的Shell有Bourne Shell(/usr/bin/sh或/bin/sh)和Bourne Again Shell(/bin/bash),sh由Steve Bourne开发,是Unix 标准默认的shell,bash由Brian Fox和Chet Ramey共同开发完成,是Linux标准默认的shell。

    创建shell脚本
    在linux中可以使用vim来编写shell script,通常使用.sh作为扩展名,sh代表shell。下面是一个简单的shell脚本:

    #!/bin/bash
    echo "Hello World !"
    

    第一行的“#!”是一个约定的标记,它告诉系统这个脚本需要哪一种解释器来执行。

    执行shell脚本
    编写完shell脚本,在执行脚本前我们需要给脚本添加执行权限,命令如下:

    chmod +x test.sh
    

    然后执行shell脚本

    ./test.sh
    

    注:./ 表示执行当前目录中test.sh脚本,如果不加./,则系统会去PATH中的目录里面查找test.sh脚本,因为当前的目录没有配置在PATH中,所以会提示找不到命令,如下所示:

    [root@pingtai-test test]# test.sh
    -bash: test.sh: command not found
    

    常用shell脚本
    1,通过shell脚本调用jar包

    #!/bin/bash
    source /etc/profile
    nohup java -jar -Xms4000m -Xmx4000m -Xmn2000m /usr/local/test/Test1.jar >> /var/log/test/log/test_$(date -d "today" +"%Y-%m-%d").log 2>&1 &
    wait
    nohup java -jar -Xms4000m -Xmx4000m -Xmn2000m /usr/local/test/Test2.jar >> /var/log/test/log/test_$(date -d "today" +"%Y-%m-%d").log 2>&1 &
    

    这个脚本用来执行两个Java程序Test1和Test2,先执行Test1,然后再执行Test2,并将日志输出到/var/log/test/log目录下面。

    2,定时清理垃圾文件

    #!/bin/bash
    #删除文件夹
    rm -rf /home/test/blacklistEnterpriseList
    rm -rf /home/test/creditReport
    rm -rf /home/test/financeList
    rm -rf /home/test/monitorEnterpriseEventUpdateList
    rm -rf /home/test/monitorEnterpriseList
    
    #创建文件夹
    mkdir /home/test/blacklistEnterpriseList
    mkdir /home/test/creditReport
    mkdir /home/test/financeList
    mkdir /home/test/monitorEnterpriseEventUpdateList
    mkdir /home/test/monitorEnterpriseList
    

    这个脚本用来清理垃圾数据,先删除文件夹及文件夹内的文件,然后新建文件夹,配成定时任务后可以定时清理历史数据,避免磁盘空间被占满。

    展开全文
  • 教你如何编写shell脚本

    千次阅读 2020-07-15 10:21:23
    在一些复杂的Linux维护工作,大量重复性的输入与交互操作不但费时费力,而且容易出错,而编写一个恰好片的shell脚本程序,可以批量处理、自动化地完成一系列维护任务,大大减轻管理员的负担。 1、shell脚本应用场景 ...

    一、shell脚本编程规范

    在一些复杂的Linux维护工作,大量重复性的输入与交互操作不但费时费力,而且容易出错,而编写一个恰好片的shell脚本程序,可以批量处理、自动化地完成一系列维护任务,大大减轻管理员的负担。

    1、shell脚本应用场景

    Shell脚本(shell scrip)就是将要执行的命令按顺序保存到一个文件文件,并给该文件可执行权限,方便一次性执行的一个程序文件。主要是方便管理员进行设置或管理,可结合各种shell控制语句以完成更复杂的操作。常用于重复性操作、批量事务处理、自动化运维、服务运行状态监控、定时任务执行等。

    2、shell编程规范

    Linux系统中的shell脚本是一个特殊的应用程序,它介于 操作系统内核与用户之间,充当一个“命令解释器”的角色,负责接收用户输入的操作指令并进行解释,将需要执行的操作传递给内核执行,并输出执行结果。

    常见的shell解释器程序有很多,使用用不同的shell脚本时,其内部指令、命令行提示等方面会存在一些区别。通过/etc/shells文件可以了解当前系统所支持的shell脚本类型。
    其中,/bin/bash是目前大多数Linux版本采用的默认shell脚本。Bash的全称为Bourne Agin Shell,是最受欢迎的开源软件之一。那么什么是“shell脚本”呢?

    简单地说,只要将平时使用的各种Linux命令按顺序保存到一个文本文件,然后添加可执行权限,这个文件就成为一个Shell脚本了。

    举例:创建第一个脚本文件
    # vim first.sh
        cd /boot/
        pwd
        ls -lh vml*
    # chmod +x first.sh //为脚本加上执行权限
    #./first.sh //(前提是要加上执行权限) (相当于 #/bin/bash first.sh 或# /bin/sh first.sh)
    

    上述first.sh脚本文件中,包括三条命令:cd/boot、pwd、ls -lh vml*。执行此脚本文件后,输出结果与依次单独执行这三条命令是相同的,从而实现了‘批量处理’的自动化过程。

    添加注释

    当然,一个合格的shell脚本程序应该遵循标准的脚本结构,而且能够输出友好的提示信息、更加容易读懂。对于代码较多、结构复杂的脚本,应添加必要的注释文字。改写后的first.sh脚本内容如下所示:

    #vim first.sh
    	#!/bin/bash      //特殊的脚本声明,表示此行以后的语句通过/bin/bash程序来解释执行
        #This is my first Shell-Script.
        cd /boot/
        echo “当前的目录位于:”
        pwd
        echo “其中以vml开头的文件包括:”
    	ls -lh vml*
    

    输出结果如下所示:

    # ./first.sh 
    当前的目录位于:
    /boot
    其中以vml开头的文件包括:
    -rwxr-xr-x. 1 root root 6.4M 99 18:40 vmlinuz-0-rescue-396e2077721a48da8ea2738c4bd8e831
    -rwxr-xr-x. 1 root root 6.4M 119 2018 vmlinuz-3.10.0-957.el7.x86_64
    
    脚本的执行方式

    直接通过文件路径”./first.sh”的方式执行脚本,要求文件本身具有X权限,在某此安全系统中可能无法满足此条件。鉴于此,Linux操作系统还提供了执行shell脚本的其他方式----指定某个shell来解释脚本语句,或者通过内部命令source(或点号”.”)来加载文件中的源代码执行。

    举例:

    # source first.sh 
    # sh first.sh
    # bash first.sh
    # ./first.sh
    

    3、管道与重定向

    由于shell脚本”批量处理”的特殊性,其大部份操作过程位于后台,不需要用记进行干预。因此学会提取、过滤执行信息变得十分重要。

    (1)管道操作

    管道操作为不同命令之间的协同工作提供了一种机制,位于管道符号”|”左边的命令输出的结果,将作为右侧命令的输入(处理对象),同一行命令中可以使用多个管道。
    在shell脚本应用中,管道操作通常用来过滤所需要的关键信息。

    例如,使用grep命令查询使用”/bin/bash”作为shell的用户名称时,会输出符合条件的整行内容,在此基础上可以结合管道操作与awk命令做进一步过滤

    【例】只输出用户名和登录shell

    # grep "/bin/bash$" /etc/passwd  
        root:x:0:0:root:/root:/bin/bash
        student:x:1000:1000:student:/home/student:/bin/bash
    

    【例】 以冒号”:”作为分隔,输出第1个和第7个区域的字符串

    其中”-F”部份用来指定分隔符号(未指定时,默认以空格或制表符分隔)。

    # grep "/bin/bash$" /etc/passwd | awk -F: '{print $1,$7}'
        root /bin/bash
        student /bin/bash
    

    【 例】 以冒号”:”作为分隔,输出第1个和第3个区域的字符串

    grep "/bin/bash$"  /etc/passwd | awk -F: '{print $1,$3}'  
       root 0
       lying 1000
    

    【例】提取/的磁盘使用率信息。

    #df -hT
        文件系统         类型    容量  已用  可用 已用% 挂载点
        /dev/mapper/centos-root xfs     17G  4.0G  13G  24% /
        devtmpfs         devtmpfs  470M   0  470M   0% /dev
        tmpfs          tmpfs   487M   0  487M   0% /dev/shm
    
    #df -hT | grep “/$” | awk ‘{print $6}’
    	24%
    
    (2)重定向操作

    Linux系统使用文件来描述各种硬件、设备等资源,如以前尝过的硬盘和分区、光盘等设备文件。用户通过操作系统处理信息的过程中,包括以下几类交互设备文件。

    标准输入(STDIN):默认的设备是键盘,文件编号为0,命令将从标准输入文件中读取在执行过程中需要的输入的数据。
    标准输出(STDOUT):默认的设备是显示器,文件编号为1,命令将执行后的输出结果发送到标准输出文件。
    标准错误(STDERR):默认的设备是显示器,文件编号为2,命令执行期间的各种错误信息发送到标准错误文件。
    在实际的Linux系统维护中,可以改变输入、输出内容的方向,而不使用默认的标准输入、输出设备,这种操作称为”重定向”
    
    重定向输入:将命令中接收输入的路径由默认的键盘改为指定的文件,使用”<”操作符。
    

    举例:给用户设置密码

    #vim pass.txt
    	 123456
    #passwd --stdin jerry < pass.txt  //将jerry的密码改成123456
    
    重定向输出:将命令的正常输出结果保存到指定的文件,使用”>”或”>>”操作符。
    
    举例:将输出结果保存到指定的文件
    #uname -p >kernel.txt   查看CPU类型
    #uname -r >kernel.txt  查看内核版本信息
    
    (3)错误重定向:2>

    将执行命令过程中出现的错误保存到指定文件,使用”2>”操作符。在实际应用中,错误重定向可用来收集程序执行的错误信息,为排错提供依据。

    2>:将错误的信息保存到指定文件
    2>>:追加到指定文件
    &>:将正常和错误信息保存到同一文件

    【例】:将备份时出现的错误信息进行保存

    # tar jcf /nonedir/etc.tgz/etc 2>error.log
    # tar jcf /nonedir/etc.tgz/etc 2>>error.log
    

    【例】 如在编译源码包的自动化脚本中,若要忽略make、make install等操作过程信息,可将其定向到空文件/dev/null。

    #vim httpd_install.sh
        #!/bin/bash
        #自动编译安装httpd服务器的脚本
        cd /usr/src/httpd-2.2.17
        ./configure --prefix=/usr/local/httpd --enable-so &>/dev/null
        make &>/dev/null
        make install &>/dev/null
        ......   //省略内容
    # chmod +x httpd_install.sh
    #./httpd_install.sh
    
    (4)编译安装软件的步骤:

    解压文件—进入到解压文件后执行. /configure进行环境配置— make 编译— makeinstall 安装软件

    二、shel脚本变量

    Shell变量用来存放系统和用户需要使用的特定参数(值),而且这些参数可以根据用户的设定或系统环境的变化而相应变化。通过使用变量,shell程序能够提供更加灵活的功能,适应性更强。

    0、常见shell变量的类型

    自定义变量、环境变量、位置变量、预定义变量

    1、定义新的变量

    格式:变量名=变量值

      注意:等号两边没有空格。变量名称需以字母或下划线开头,名称中不要包含特殊字符:
    (+ - * / . ? % & #)
    

    【例】定义变量Product(值为Weixin),Version(值为6.0)

    # Product=Weixin
    # Version=6.0
    
    (1)查看和应变量的值

    引用变量值:在变量名称前添加”$”

    查看变量值:使用echo命令,可以在一条echo命令同时查看多个变量值。

    # echo $Product
    	Weixin
    # echo $Product$Version
    	Weixin6.0  因为输出变量时是连在一起的所以结果也挨在一起
    

    当变量名称容易和紧跟其后其他字符相混淆时,需要添加”{}”将其括起来,否则将无法确定正确的变量名称。对未定义的变量,将显示空值。

    # echo $Prouduct4.5
    # echo ${Product}4.5
    
    (2)变量赋值的特殊操作
    (a)双引号(””)-空格、引用其他变量

    双引号主要起界定字符串的作用,特别是当要赋值的内容包含空格时,必须以双引号括起来;其他情况下双引号通常可以省略。

    【例】变量值包含空格的正确赋值方法

    # Weixin=weixin 4.5
    	bash: 4.5: 未找到命令...
    # Weixin="weixin 4.5"
    

    在双引号范围内,使用$符号可以引用其他变量的值(变量引用)。

    # Version=8.0
    # QQ="QQ$Version"
    # echo $QQ
    	QQ8.0
    
    (b)单引号(’ ’)–特殊意义

    当要赋值的内容包含$ “ \等具有特殊含义的字符时,应使用单引号括起来。在单引号的范围内,将无法引用其他变量的值,任何字符均作为普通字符看待。但赋值内容中包含单引号时,需要使用\进行转义,以免冲突。

    举例:使用单引号对变量赋值

    # A='ABC$Version'
    # echo $A
    	ABC$Version
    # AA='AA'\'$Version\'
    # echo $AA
    	AA'6.0'
    
    # AA=AA\''$Version'\'
    # echo $AA
    	AA'$Version'
    
    ©反撇号(`)-将命令结果赋值给变量,嵌套以$()代替

    主要用于命令替换,允许执行某个命令的屏幕输出结果赋值给变量。反撇号括起来的范围内必须是能够执行的命令行,否则会出错。

    【例】在一行命令中查找tar命令程序的位置并列出其详细属性。

    # ls -lh `which tar`
    	-rwxr-xr-x. 1 root root 339K 1031 2018 /usr/bin/tar
    

    【例】提取vsftpd服务的封禁用户列表,并将其赋值给变量Denylist

    # Denylist=`grep -v "^#" /etc/vsftpd/ftpusers`  //-v表示反向选择,^#表示以#开头的 ^$表示空行
    # echo $Denylist
    	root bin daemon adm lp sync shutdown halt mail news uucp operator games nobody
    

    注意:使用反撇号难以在一行命令中实现嵌套命令替换操作,这时可以使用$()来代替反撇号操作,以解决嵌套的问题。

    【例】查询提供useradd命令程序的软件包所安装的配置文件位置

    # rpm -qc $(rpm -qf $(which useradd))
        /etc/default/useradd
        /etc/login.defs
    
    (d)read 参数
    参数 含义
    -t 输入等待时间(单位:秒)
    -p 提示信息

    read命令用来提示用户输入信息,从而实现简单的交互过程。执行时将从标准输入设备读入一行内容,并以空格为分隔符,将读入的各字段挨个赋值给指定的变量(多余的内容赋值给最后一个变量)。若指定的变量只有一个,则将整行内容赋值给此变量。

    举例:使用read命令,以输入的方式给变量赋值(相当于input -print)

    # read ToDir1
    	输入:123456
    # echo $ToDir1
    	123456
    

    read命令可以结合-p和-t选项来设置提示信息和输入等待时间(单位默认为秒)

    # read -p "please input directory:" -t 3 AA   //等待3秒钟,变量名为AA 输入的值将赋值给AA
    	please input directory:/mnt/bak  #输入一个值
    # echo $AA
    	/mnt/bak
    
    (3)设置变量的作用范围-默认为局部变量

    默认情况下,新定义的变量只在当前的shell环境中有效,因此称为局部变量。当进入子程序或新的子shell环境时,局部变量将无法再使用。

    # Weixin=weixin
    # Version=6.0
    # echo "$weixin $Version"
    	weixin 6.0
    
    #bash
    echo "$weixin $Version"
    
    (4)全局变量 export

    为了使用定义的变量在所有的子shell环境中能够继续使用,减少重复设置工作,可以通过内部命令export将指定的变量导出为”全局变量”。可以同时指定多个变量名称作为参数(不需要使用$),变量名之间以空格分隔。

    # export weixin Version
    # bash
    # echo "$weixin $Version"
    	weixin 6.0
    
    使用export导出全局变量的同时,也可以为变量进行赋值。
    
    #export KGC=”www.kgc.cn”
    # echo $KGC
    	www.kgc.cn
    
    (4)数值变量的运算

    shell变量的数值运算多用于脚本程序的过程控制(如循环次数、使用量比较等)。在Bash Shell环境中,只能进行简单的整数运算,不支持小数运算。

    整数值的运算主要通过expr进行,基本格式如下:

    expr 变量1 运算符 变量2 [运算符 变量3]…

    其中,变量对应需要计算的数值变量(需要以”$”符号调用),常用的几种运算符如下:

    运算符 意义
    ++ – 增加及减少,可前置也可放到结尾
    * / % 乘法、除法、取余
    + - 加法、减法
    < <= > >= 比较符号
    == != 等于与不等于
    & 位的与
    ^ 位的异或
    | 位的或
    && 逻辑的与
    || 逻辑的或
    ?: 条件表达式
    = += -= *= /= %= &= ^= <<= >>= |= 赋值运算符a+=相当于a=a+1

    【例】两个整数运算 X=35 Y=16 整数运算 expr

    #X=35
    #Y=16
    #expr $X + $Y
    #expr $X - $Y
    #expr $X \* $Y
    #expr $X / $Y
    #expr $X % $Y
    #Ycube=`expr $Y \* $Y \* $Y`
    

    使用expr进行计算的时候,变量必须是整数,不能是字符串,也不能含小数,否则会出错

    除了expr命令外,变量数值常见的命令还包括:(())、let等。如果要执行简单的整数运算,只需要将特定对的算术表达式用$(())括起来即可。

    【例】简单的算术运算

    #bb=$((1+2**3-4))
    #echo $((1+2**3-4))
    

    【例】set 查看定义的变量

    # unset Serversion  //取消变量
    # readonly 变量名    //设置只读变量,unset不能删除只读变量
    

    2、特殊变量

    (1)环境变量

    环境变量指的是出于运行需要而由Linux系统提前创建的一类变量,主要用于设置用户的工作环境,包括用户主目录、命令查找路径、用户当前目录、登录终端等。环境变量的值由Linux系统自动维护,随用户状态的改变而改变。

    使用env命令可以查看到当前工作环境下的环境变量,对于常见的一些环境变量就了解其各自的用途。

    PATH变量用于设置可执行程序的默认搜索路径,当仅指定文件名称来执行命令程序时,Linux系统将在PATH变量指定的目录范围查找对应的可执行文件,如果找不到则会提示”command not found”,此时修改PATH变量或将脚本文件复制到环境变量搜索目录下。

    举例:向PATH环境变量添加脚本文件目录

    # echo $PATH
    	/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/root/bin
    	/root/first.sh
    
    # first.sh
    	bash: first.sh: 未找到命令...
    # PATH=”$PATH:/root”
    # first.sh  #因为配置了PATH所以可以直接执行命令
    

    在Linux系统中,环境变量的全局配置文件为/etc/profile,在此文件中定义的变量

    作用于所有用户。除此外,每个用户还有自己的独立配置文件(~/.bash_profile)。若要长期变更或设置某个环境变量,应在上述文件中进行设置。

    【例】修改历史记录命令条数

    # history | wc -l
    # vim /root/.bash_profile 
    	export HISTSIZE=50
    # source /root/.bash_profile 
    # history | wc -l
    
    (2)数值变量–bc运算符
    1-直接定义成数值变量:
    # declare -i a=100
    # a=$a2
    
    2-使用双圆括号:
    # a=100
    # a=$(($a/2))
    
    3-使用expr命令:
    # a=100
    # a=`expr $a / 100`
    
    4-bc运算符
    # [root@localhost lying]# echo 100 /10|bc
    # 10
    
    # bc表示运算符,不加bc就会原样输出
    

    【例】整数运算

    #  a=100
    #  b=33
    # [root@localhost ~]#echo "$a/$b"| bc
    #  3
    

    【例】保留两位小数运算

    #  [root@localhost ~]# echo "scale=2;$a/$b" | bc
    
    (3)位置变量

    为了在使用shell脚本程序时, 方便通过命令行为程序提供操作参数,bash引入了位置变量的概念。当执行命令时,第一个字段表示命令表示命令名或脚本程序名,其余的字符串参数按照从左到右的顺序依次赋值给位置变量。

    位置变量也称为位置参数,使用$1 $2 $3 …$9表示。

    #!/bin/bash
        SUM=`expr $1 + $2`
        echo "$1+$2"= $SUM
    # chmod +x addr2num.sh 
    # ./addr2num.sh 15 20
        15 +  20= 35
        
    set 1 2 3  #指定$1=1 $2=2 $3=3
    
    (4)预定义变量

    预定义变量是由Bash程序预先定义好的一类特殊变量,用户只能使用预定义变量,而不能创建新的预定义变量,也不能直接为预定义变量赋值。预定义变量使用$符号和另一个符号组合表示,常见的有:

    $#:表示命令行中位置参数的个数
    $*:表示所有位置参数的内容
    $?:表示前一条命令执行后的返回状态,返回值为0表示正确执行,返回值为不为0则表示执行异常
    $0:表示当前执行的脚本或程序名称
    
    $0       相当于C语言main函数的argv[0]
    $1 $2 $3....位置参数,相当于argv[1],argv[2],argv[3]
    $#       相当于argv -1
    $@      表示参数列表(可以用做for的遍历)
    $*        表示参数列表
    $?       上一条命令的exit status(0为真  非0为假)
    $$       当前进程号
    shift     会使参数列表右移一位
    
    
    #!/bin/bash
    T=`date "+%Y%m%d-%H%M"`  #设置时间 
    TARFILE=beifen-${T}.tgz  #备份后的文件名 
    tar zcf $TARFILE $* &>/dev/null  #将所有文件备份名为$TARFILE 的打包正确错误信息设置为不显示
    echo "已执行$0脚本"
    echo "共完成$#个对象的备份"
    echo "具体内容包括:$*"
    
    chmod +x mybak.sh
    
    # ./mybak.sh /boot/grub /mnt/public /root/aa
        已执行./mybak.sh脚本
        共完成1个对象的备份
        具体内容包括:/boot/grub
    

    3、整数值比较

    整数值比较指的是根据给定的两个整数值,判断第一个数与第二个数的关系,如是否是大于、等于、小于第二个数。整数值比较的常用操作选项如下:

    -eq  a等于b
    -ne  a不等于b
    -gt  a大于b
    -lt  a小于b
    -le  a小于或等于b
    -ge  a大于或等于b
    

    ​ 整数值比较在shell脚本编写中的应用较多,例如用来判断已登录用户数量、开启进程数、磁盘使用率是否超标,以及软件版本号是否符合要求等。实际使用时,往往会通过变量引用、命令替换等方式来获取一个数值。

    【例】判断当前已登录用户数,当超过5个时输出“Too many”

    # Unum=`who|wc -l`
    # [ $Unum -gt 5 ]&&echo "too many."
    too many.
    

    【例】判断当前可用空闲内存(free)大小,当低于1024MB时输出具体数值

    # FreeCC=$(free -m|grep Mem|awk '{print $4}')
    # [ $FreeCC -lt 1024 ]&&echo ${FreeCC}MB
    

    4、字符串比较

    字符串比较通常用来检查用户输入、系统环境变量等是否满足条件,在提供交互式操作的shell脚本中,也可用来判断用户输入的位置参数是否符合要求。字符串比较常用的操作选项如下:

    =   第一个字符串与第二个字符串相同
    !=  第一个字符串与第二个字符串不相同
    -z   检查字符串为空(zero),对于未定义或赋予空值的变量将视为空串
    

    三、任务练习

    任务一:对apache进行日志备份?要求在每天晚上12:00进行一次备份,每天一个文件?
    apache日志文件:/var/log/httpd
    有两个配置文件: access_log  访问日志
    			   error_log  错误日志
    每天晚上12:00进行一次备份-周期性计划任务-crontab 
    
    1)编写shell脚本使之可以备份
    vim /home/lying/first.sh
        #! /bin/bash
        T=`date "+%Y%m%d-%H:%M"`
        cp /var/log/httpd/error_log /var/log/httpd/error_log_${T}.bak
        cp /var/log/httpd/access_log /var/log/httpd/access_log_${T}.bak
        echo "已执行$0 脚本"
        echo "共完成$# 个对象的备份"
        echo "具体内容为$* "
    
    2)编写周期性计划任务执行shell脚本
    crontab -u root -e 
    	00 00 * * * /home/lying/first.sh
    	此处为了测试将时间设置为当前时间 
    	39 16 * * * /home/lying/first.sh
    3)查看邮件--成功
    mail -u root
        Heirloom Mail version 12.5 7/5/10.  Type ? for help.
        "/var/mail/root": 1 message 1 new
        >N  1 (Cron Daemon)         Tue Jun 16 16:39  27/935   "Cron <root@localhost>"
    
    任务二:写一个脚本,判断apache是否已经安装?如果已安装,请打印“apache软件已安装”,并启动服务。如果没有安装?请安装并启动服务?
    if语句的使用?
    
    是否安装怎么判断? rpm -qa | grep httpd-----$?  
    
    如果是0:表示已安装,如果是1表示未安装。
    
    1)编辑shell脚本程序
    vim /home/lying/apa.sh
        #!/bin/bash
        /usr/bin/rpm  -qa |grep httpd &>/dev/null
        if [ $? -eq 0 ]
        then
        echo "apache已经安装可以使用啦"
        else
        echo "没有安装apache,将安装"
        yum install httpd
        fi
    
    
    2)运行程序
     cd /home/lying
     ./apa.sh
    
    任务三:写一个脚本对服务器的CPU、内存、硬盘使用空间进行监测?
    1)vim /home/lying/cpu.sh
        #!/bin/bash
        free -m |grep Mem | awk '{print "当前系统内存哦:" $2"MB " "已使用:" int ($3/$2*100)"%"}'
        top -n 1 |grep Cpu | awk '{print "当前系统的cpu使用率:" (100-$8)"%"}'
        df -hT | awk 'NR == 2 { print $1 " 分区容量:"$3" 已使用:"$6}'
    2)让cpu.sh有执行的权限 
    chmod +x /home/lying/cpu.sh
    3)运行
    ./cpu.sh
    

    top命令可以看到总体的系统运行状态和cpu的使用率

    %us:表示用户空间程序的cpu使用率(没有通过nice调度)
    %sy:表示系统空间的cpu使用率,主要是内核程序。
    %ni:表示用户空间且通过nice调度过的程序的cpu使用率。
    %id:空闲cpu
    %wa:cpu运行时在等待io的时间
    %hi:cpu处理硬中断的数量
    %si:cpu处理软中断的数量
    %st:被虚拟机偷走的cpu
    
    任务四:定一个一键配置本地yum源的shell脚本
    
    

    四、条件语句

    一、条件测试

    使用shell脚本程序具备一定的“智能”,面临的第一个问题就是如何区分不同的情况以确定执行何种操作。例如,当磁盘使用率超过95%时发送警告信息;当备份目录存在时能够自动创建;当源码编译程序时若配置失败则不再继续安装等。
    
    shell环境根据命令执行后的返回状态($?)来判断是否执行成功:
    当返回0时表示成功
    当返回1时表示失败或异常
    
    test命令–对特定条件进行测试,并根据返回值来判断是否成立。
     test命令的使用:test 条件表达式  或  [ 条件表达式 ]
    
     	这两种方式的作用完全相同,但通常后一种形式更为常用,也更贴近编程习惯。需要注意的是,方括号与条件表达式之间需要至少一个空格进行分隔。
    	
    根据需要测试的条件类别不同,条件表达式也不同。比较常用的条件操作包括文件测试、整数值比较、字符串比较、以及针对多个条件的逻辑测试。
    
    1-文件测试-test

    ​ 文件测试指的是根据给定的路径名称,判断对应的是文件还是目录,或者判断文件是否可读、可写、可执行等。文件测试的常见操作选项如下,使用时将测试对象放在操作选项之后即可。

    -d 测试是否为目录(Directory)
    -e 测试目录或文件是否存在(Exist)
    -f 测试是否为文件(File)
    -r 测试当前用户是否有权限读取(Read)
    -w 测试当前用户是否有权限写入(Write)
    -x 测试是否设置有可执行(Excute)权限
    -s 如果文件存在且文件大小(Size)大于零,则为True
    
    -r File 如果文件File存在且是可读的(Readable),则为True
    -w File 如果文件File存在且是可写的(Writable),则为True
    -x File 如果文件File存在且是可执行的(Executable),则为True
    -O File 如果文件File存在且属于当前用户(Owner),则为True
    -G File 如果文件File存在且属于当前用户组(Group),则为True
    -b File 如果文件File存在且是块(Block)特殊文件,则为True
    -c File 如果文件File存在且是字符(Character)特殊文件,则为True
    -L File 如果文件File存在且是符号链接(Link)文件,则为True
    
    

    【例】判断/mnt/cdrom目录是否存在?

    # test -e /mnt/cdrom
    # echo $?
    0
    

    【例】判断/mnt/cdrom是不是目录?

    # test -d /mnt/cdrom
    # echo $?
    0
    
    //或
    # [ -d /mnt/cdrom ]
    # echo $?
    0
    

    【例】查看目录是否存在

    #[ -e /media/cdrom ]&&echo “YES”
               //无输出表示该目录不存在
    YES       //输出“YES”表示该目录存在
    

    【例】查看是否为目录

    # [ -d /media/cdrom ]&&echo “YES” || echo “NO”
    
    1-2使用[[ …… ]]条件测试
    # [[ -d /media/cdrom ]]&&echo “YES” || echo “NO”
    
    1-3 test两个文件的比较

    test命令中用于判断文件的选项有很多,从文件个数上可分为单个文件的判断和两个文件之间的比较。其-中判断单个文件最常用的选项就-f选项,在比较两个文件时,常用的选项有:

    -nt 判断文件A是否比文件B新
    -ot 判断文件A是否比文件B旧
    -ef 判断两个文件是否为同一个文件,用来判断两个文件是否指向同一个inode
    

    【例】

    #touch a
    #touch b
    #test a -ot b&&echo “YES” || echo “NO”
    #[ a -ot b ]&&echo “YES” || echo “NO”
    #test a -ef b &&echo “YES” || echo “NO”
    #ln a c
    #test a -ef c &&echo “YES” || echo “NO”
    
    2、整数值比较

    整数值比较指的是根据给定的两个整数值,判断第一个数与第二个数的关系,如是否是大于、等于、小于第二个数。整数值比较的常用操作选项如下:

    -eq  a等于b
    -ne  a不等于b
    -gt  a大于b
    -lt  a小于b
    -le  a小于或等于b
    -ge  a大于或等于b
    

    ​ 整数值比较在shell脚本编写中的应用较多,例如用来判断已登录用户数量、开启进程数、磁盘使用率是否超标,以及软件版本号是否符合要求等。实际使用时,往往会通过变量引用、命令替换等方式来获取一个数值。

    【例】判断当前已登录用户数,当超过5个时输出“Too many”

    # Unum=`who|wc -l`
    # [ $Unum -gt 5 ]&&echo "too many."
    too many.
    

    【例】判断当前可用空闲内存(free)大小,当低于1024MB时输出具体数值

    # FreeCC=$(free -m|grep Mem|awk '{print $4}')
    # [ $FreeCC -lt 1024 ]&&echo ${FreeCC}MB
    
    3、字符串比较

    字符串比较通常用来检查用户输入、系统环境变量等是否满足条件,在提供交互式操作的shell脚本中,也可用来判断用户输入的位置参数是否符合要求。字符串比较常用的操作选项如下:

    =   第一个字符串与第二个字符串相同
    !=  第一个字符串与第二个字符串不相同
    -z   检查字符串为空(zero),对于未定义或赋予空值的变量将视为空串
    

    【例】判断当前系统的语言环境,不是en.US时输出“Not en.US”

    # echo $LANG
    zh_CN.UTF-8
    # [ $LANG != "en.US" ]&&echo "Not en.US"
    Not en.US
    

    【例】在shell脚本应用中,经常需要用户输入yes或no来确认某个任务

    # read -p "是否覆盖现有文件(yes/no)?" ACK
    是否覆盖现有文件(yes/no)?yes
    # echo $ACK
    yes
    # [ $ACK = "yes" ]&&echo "覆盖"
    # read -p "是否覆盖现有文件(yes/no)?" ACK
    是否覆盖现有文件(yes/no)?no
    # [ $ACK = "no" ]&&echo "不覆盖"
    不覆盖
    
    4、逻辑测试

    逻辑测试指的是判断两个或多个条件之间的依赖关系。当系统任务取决于多个不同的条件时,判断是根据这些条件同时成立还是只要有其中一个成立等情况,需要有一个测试的过程,常用的逻辑测试操作如下,使用时放在不同的测试语句或命令之间。

    	&&   逻辑与,表示而且,只有当前后两个条件都成立时,整个测试的命令返回值才为0(结果成立)。使用test命令测试时可改为-a
    	||   逻辑或,表示或者,只要前后两个条件有一个成立,则整个测试的命令返回值为0(结果成立)。使用test命令测试时可改为-o
    	!    逻辑否,表示不,只有当指定的条件不成立时,整个测试命令的返回值才为0(结果成立)
    

    举例:判断Linux系统的内核版本是否大于2.4

    # Mnum=$(uname -r|awk -F. '{print $1}')
    # Snum=$(uname -r|awk -F. '{print $2}')
    #[ $Mnum -gt 2 ]&&[$Snum -gt 4]&&echo "yes" || echo "no"
    #[ $Mnum -eq 2 ]&&[$Snum -gt 4]&&echo "yes" || echo "no"
    #[ $Mnum -gt 2 ]||`[ $Mnum -eq 2 ]&&[$Snum -gt 4]`&&echo "yes" || echo "no"
    
    [root@localhost ~]# test $Mnum -eq 3 -a $Snum -gt 4
    [root@localhost ~]# echo $?
    0
    [root@localhost ~]# test $Mnum -eq 2 -a $Snum -gt 4
    [root@localhost ~]# echo $?
    1
    

    二、if语句结构

    在shell脚本应用中,if语句是最为常用的一种流程控制方式,用来根据特定的条件测试结果,分别执行不同的操作(如果…那么…)。根据不同的复杂程度,if语句的选择结构可以分为三种基本类型,适用于不同的应用场合。

    1、单分支的if语句

    只有在条件成立时才会执行相应的代码,否则不执行任何操作。

    语法格式:

    if 条件测试语句
    then  
         命令序列
    else
         命令序列
    fi
    

    【例】使用shell脚本挂载光盘,并进行永久挂载

    #!/bin/bash
    MOUNT_DIR="/mnt/cdrom"
    if [ ! -d $MOUNT_DIR ]
    then
     mkdir -p $MOUNT_DIR
     mount /dev/sr0 $MOUNT_DIR
    else
     echo -e "\033[31m /dev/sr0 mounted on /mnt/cdrom!\033[0m"
    fi
    
    # chmod +x moutcd.sh 
    # ./moutcd.sh
    

    【例】有些特权命令要求root用户执行,如果当前用户不是root,那么就提示权限不足。

    #!/bin/bash
    if [ "$USER" != "root" ]
    then
      echo -e "\033[31m 错误:非root用户,权限不足!\033[0m"
      exit 1
    fi
    fdisk -l /dev/sda
    
    2、双分支的if语句

    针对条件成立和条件不成立两种情况分别执行不同的操作。

    语法格式:

       if 条件测试语句
       then  
         命令序列1
       else
         命令序列2
       fi
    

    【例】使用shell脚本测试主机是否开启

    #!/bin/bash
    ping -c 3 -i 0.2 -w 3 $1 &>/dev/null
    if [ $? -eq 0 ]
    then
     echo "Host $1 is up!"
    else
     echo "Host $1 is down!"
    fi
    
    # ./pinghost.sh 192.168.75.1
    Host 192.168.75.1 is up!
    

    【例】 通过shell命令检查vsftpd服务是否运行,如果已经运行则列出其监听地址、PID号,否则输出“警告:vsftpd服务不可用”,其中pgrep -x表示精确匹配。

    #!/bin/bash
    /usr/bin/systemctl status vsftpd &>/dev/null
    if [ $? -eq 0 ]
    then
      echo "监听地址:$(netstat -anpt | grep vsftpd | awk '{print $4}')"
      echo "进程PID号:$(pgrep -x vsftpd)"
    else
      echo "警告:vsftpd服务不可用!"
    fi
    
    #chmod +x chkftpd.sh
    # ./chkftpd.sh 
    监听地址::::21
    进程PID号:102825
    
    3、多分支的if语句

    与单分支、双分支的if语句相比,多分支if语句的实际应用并不多见。由于if语句可以根据测试结果的成立、不成立分别执行操作,所以能够嵌套使用,进行多次判断。

    语法格式:

     if 条件测试操作1
       then  
         命令序列1   
    elif 条件测试操作2
    
    then  
        命令序列2
        elif 条件测试操作2
    then  
         命令序列2
    eles
         命令序列3
    fi	
    

    【例】输入分数判断优良差

    #vim gradediv.sh
    #!/bin/bash
    read -p "请输入您的分数(0-100):" GRADE
    if [ $GRADE -ge 85 ]&&[ $GRADE -le 100 ]
    then
      echo "$GRADE分!优秀"
    elif [ $GRADE -ge 70 ]&&[ $GRADE -le 84 ]
    then 
    echo "$GRADE分,合格"
    else 
    echo "$GRADE分?不合格"
      fi
    # chmod +x gradediv.sh 
    # ./gradediv.sh 
    

    五、case语句与循环语句

    一、使用case分支语句

    1、case语句的结构
    case 变量值 in  #变量值即“$变量名”
        模式 1)
        命令序列1
        ;;
    
        模式 2)
        命令序列2
        ;;
        .......
    
        *)
        默认命令序列
        esac
    

    关键字case后面跟的是“变量值”,即“$变量名”,这点需要与for循环语句的结构加以区分。整个分支结构包括在case … esac之间。中间的模式1、模式2 … 对应为变量的不同取值(程序期望的取值),其中作为通配符,可匹配任意值。

    case语句的执行流程:首先“变量值”与模式1进行比较,若取值相同则执行模式1后面的命令序列,直到遇见“;;”后跳转至esac,表示结束分支;若与模式1不匹配,则继续模式2进行比较,若取值相同则执行模式2后面的命令序列,直到遇见“;;”后跳转至esac,表示结束分支…以此类推;若找不到任何匹配的值,则执行默认模式“*)”后的命令序列,直到遇见“;;”后结束分支;

    注意:
    case行尾必须为单词“in”,每一模式必须以右括号“)”结束。
    双分号“;;”表示命令序列的结束。
    模式字符串中,可以用方括号表示一个连续的范围,如[0-9];还可以用竖杠符号“|”表示或,如A|B。
    最后“*)”表示默认模式,其中*相当于通配符。
    
    2、case语句应用示例
    # vim hitkey.sh
        #!/bin/bash
        read -p "请输入一个字符,并按Enter键确认:" KEY
        case "$KEY" in
        [a-z]|[A-Z])
        echo "您输入的是字母: $KEY"
        ;;
        [0-9])
        echo "你输入的是数字: $KEY"
        ;;
        *)
        echo "您输入的是空格、功能键或其他控制字符!"
        esac
    # chmod +x hitkey.sh 
    #./hitkey.sh
    

    二、使用for循环语句

    1、for循环语句的语法结构
    for 变量名 in  取值列表
    do
    命令序列
    Done
    

    ​ for语句结构中,for语句的操作对象为用户指定名称的变量,并通过in关键字为该变量预先设置了一个取值列表,多个取值之间以空格进行分隔。位于do … done之间的命令序列称为循环体,其中的执行语句需要引用变量以完成相应的任务。

    for语句的执行流程:首先将列表中的第1个取值赋值给变量,并执行do .... done循环体中的命令序列;然后将列表中的第2个取值赋值给变量,并执行循环体中的命令序列....以此类推,直到列表中的所有取值用完,最后将跳至done语句,表示结束循环。
    
    2、for语句应用示例
    (1)根据姓名列表批量添加和删除用户
    # vim /root/users.txt  //用做测试的列表文件
        chenye
        dengchao
        zhangjie
    
    # vim uaddfor.sh		//批量添加用户的脚本
        #!/bin/bash
        ULIST=$(cat /root/users.txt)
        for UNAME in $ULIST  //变量UNAME的取值范围为 $ULIST
        do
            useradd $UNAME
            echo "${UNAME}已创建成功"
            echo "123456" | passwd --stdin $UNAME &>/dev/null  //设置每个用户的密码为123456 且不显示提示信息
        done
        
    # chmod +x uaddfor.sh
    # ./uaddfor.sh		//测试并确认执行结果
    # tail -3 /etc/passwd
    chenye:x:1011:101 1:/home/chenye:/bin/bash
    dengchao:x:1012:1012:/home/dengchao:/bin/bash
    zhangjie:x:1013:03:/home/zhangjie:/bin/bash
    
    # vim udelfor.sh		//批量删除用户的脚本
        #!/bin/bash
        ULIST=$(cat /root/users.txt)
        for UNAME in $ULIST
        do
        userdel -r $UNAME &>/dev/null
        done
        
    # chmod +x udelfor.sh
    # ./udelfor.sh			//测试并确认执行结果
    # id chenye
    id: chenye:无此用户
    
    (2)根据IP地址列表检查主机状态
    # vim /root/ipadds.txt	//用做测试的列表文件
        192.168.4.11
        192.168.4.110
        192.168.4.120
    # vim chkhosts.sh		//循环检查各主机的脚本
        #!/bin/bash
        HLIST=$(cat /root/ipadds.txt)
        for IP in $HLIST
        do
        ping -c 3 -i 0.2 -W 3 $IP &> /dev/null
        if [ $? -eq 0 ]
        then
        echo "Host $IP is up."
        else
        echo "Host $IP is down."
        fi
        done
    
    # chmod +x chkhosts.sh
    # ./chkhosts.sh		//测试并确认执行结果
    Host 192.168.4.11 is up.
    Host 192.168.4.110 is down.
    Host 192.168.4.120 is up.
    

    三、使用while循环语句

    1、while循环语句的语法结构
    while 条件测试操作
    do
    命令序列
    done
    
    2、while语句应用示例
    (1)批量添加规律编号的用户

    批量添加用户

    # vim uaddwhile.sh
        #!/bin/bash
        PREFIX="stu"
        i=1
        while [ $i -le 20 ]
        do
            useradd ${PREFIX}$i
            echo "123456" | passwd --stdin ${PREFIX}$i &> /dev/null
            let i++
        done
    # chmod +x uaddwhile.sh
    # ./uaddwhile.sh
    
    (2)批量删除规律编号的用户
    # vim udelwhile.sh
        #!/bin/bash
        PREFIX="stu"
        i=1
        while [ $i -le 20 ]
        do
            userdel -r ${PREFIX}$i
            let i++
        done
    # chmod +x udelwhile.sh
    # ./udelwhile.sh
    
    (3)猜价格游戏
    # vim pricegame.sh
        #!/bin/bash
        PRICE=$(expr $RANDOM % 1000)
        TIMES=0
        echo "商品实际价格范围为0~999,猜猜看是多少?"
        while true
        do
            read -p "请输入你猜测的价格数目:" INT
            let TIMES++
            if [ $INT -eq $PRICE ];then
            	echo "恭喜你答对了!实际价格是$PRICE"
                echo "你总共猜测了$TIMES次"
                exit 0
            elif [ $INT -gt $PRICE ];then
                echo "太高了!"
            else
                echo "太低了!"
            fi
        done
    
    # chmod +x pricegame.sh
    # ./pricegame.sh
    

    四、Shell函数应用

    1、定义函数的语法结构
    [function]函数名(){
    命令序列
    [return x]
    • [function]是可选的,表示该函数的功能,是可以省略的;
    • ()跟在函数名后,里面是没有内容的;
    • {}我们所需要执行的命令序列放在这里面;
    • [return x] 当命令序列执行完后返回给系统一个值,是可以省略的。
    • 在脚本中调用函数的方式是直接输入函数名即可,有时还需要输入一些参数。
    2、定义并调用函数的应用示例

    定义一个求和函数并在脚本中引用

    #!/bin/bash
    sum(){
        read -p "Please Input First number:" NUM1
        read -p "Please Input Second number:" NUM2
        echo "The numbers is:$NUM1 and $NUM2"
        SUM=$(($NUM1+$NUM2))
        echo "The Sum is :$SUM"
    }
    
    sum  //引用函数
    
    #chmod +x sum.sh
    #./sum.sh
    

    在Linux系统中有很多服务启动脚本定义了丰富的shell函数,并嵌套了各种语句,如if语句等。我们在编写服务启动脚本可参考系统原有的启动脚本编写。

    五、shell脚本调试

    在排错时要注意把复杂的脚本简单化,要思路清晰,并且分段实现。当执行脚本时出现脚本错误后,不要只看那些提示的错误行,而是要观察整个相关的代码段。为避免编写的脚本出错,除了在编写脚本时注意书写规范,排除语法错误,更重要的是利用调试脚本工具来调试脚本。

    (1)使用echo命令进行调试

    echo命令是最有用的调试脚本工具之一,一般在可能出现问题的脚本中加入echo命令,采用的是分段排查的方式。

    (2)使用bash命令参数进行调试
    格式:
    sh [-nvx] 脚本名
    
    参数含义:
    -n 不会执行该脚本,仅查询脚本语法是否有问题,如果没有语法问题就不显示任何内容,如果有问题就会报错。
    -v 在执行脚本时,先将脚本的内容输出到屏幕上然后执行脚本,如果有错误,也会给出提示。
    -x 将执行的脚本内容输出到屏幕上,当脚本文件较长时,可以使用set命令指定调试一段脚本
    
    (3)使用set命令指定调试脚本段落
    vim tiao.sh
        #!/bin/bash
        set -x ###开启调试模式###
        read -p "请输入您的分数(0-100):" GRADE
        if [ $GRADE -ge 85 ]&&[ $GRADE -le 100 ]
            then
            echo "$GRADE分!优秀"
        set +x ###关闭调试模式###
            elif [ $GRADE -ge 70 ]&&[ $GRADE -le 84 ]
            then 
            echo "$GRADE分,合格"
            else 
            echo "$GRADE分?不合格"
        fi
    
    或者 
    set -x #开启调试模式 
    ./tiao.sh 输出调试模式下的脚本
    set +x #关闭调试模式
    ./tiao.sh 输出正常的脚本 
    

    六、Shell编程之Sed与Awk

    一、正则表达式概述

    文本处理工具 基础正则表达式 扩展正则表达式
    vi编辑器 支持
    grep 支持
    egrep 支持 支持
    sed 支持
    awk 支持
    1.基础正则表达式元字符
    \	转义字符,用于取消特殊符号的含义,如:\!、\n等
    ^	匹配字符串的开始位置,如: ^world 匹配以world 开头的行
    $	匹配字符串的结束位置,如: world$ 匹配以world结尾的行
    
    .			匹配除\n (换行)之外的任意一个字符
    *			匹配前面的子表达式0次或者多次
    [list]		匹配list列表中的一个字符,如: [0-9] 匹配任一位数字
    [^list]		匹配不在list 列表中的一个字符,如: [^0-9] 匹配任意-位非数字字符
    \{n\}		匹配前面的子表达式n次,如: [0-9]\{2\} 匹配两位数字
    \{n,\}		匹配前面的子表达式不少于n次,如: [0-9]\{2,\} 表示两位及两位以上数字
    \{n,m\}		匹配前面的子 表达式n到m次,如: [a-z]\{2,3\} 匹配两到三位的小写字母
    
    -v 表示取反
    -e 表示参数查找多个模式
    
    2.扩展正则表达式
    +	匹配前面的子表达式1次以上,如: go+d, 将匹配至少一个o
    ?	匹配前面的子表达式0次或者1次,如go?d,将匹配gd或god
    0	将0号中的字符串作为一个整体,如: (xzy)+, 将匹配xzy整体1次以上
    |	以或的方式匹配字符串,如:good|great,将匹配good或者great
    
    3.grep工具

    【例】以/etc/passwd 文件为例,介绍基础正则表达式。

    注意,/etc/passwd 文件由于系统差异,可能会与案例中输出的结果有所不同。

    [root@localhost ~]# grep root /etc/passwd		//筛选文件中包含root的行
    
    [root@localhost ~]# grep ^root /etc/passwd		//筛选出以root开头的行
    root:x:0:0:root:/root:/bin/bash
    
    [root@localhost ~]# grep bash$ /etc/passwd		//筛选出以bash结尾的行
    root:x:0:0:root:/root:/bin/bash
    
    [root@localhost ~]# grep -v root /etc/passwd		//筛选文件中不包含root的行
    
    [root@localhost ~]# grep 'r..d’ /etc/passwd			//筛选出r和d之间有两个字符的行
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    
    [root@localhost ~]# grep '[^s]bin' /etc/passwd		//筛选bin前面不是S的行
    [root@localhost ~]# grep "^$" /etc/passwd			//筛选出空白行,没有空白行所以没输出
    [root@localhost ~]# grep 't[es]' /etc/passwd		//筛选包含字符串te或ts的行
    [root@localhost ~]# grep '0\{1,\}' /etc/passwd		//查找数字0出现1次及以上的行
    [root@localhost ~]# grep -e "ntp" -e "root" /etc/passwd  	//-e 参数查找多个模式
    
     
    

    当使用连续的字符时,例如小写英文、大写英文、数字,就可以使用[a-z], [A-Z], [0-9] 的方式书写。

    [root@localhost ~]# grep [0-3] /etc/passwd				//筛选包含数字0~3的行
    [root@localhost ~]# grep '[^a-z]ae' /etc/passwd		//筛选ae前面不是小写字母的行
    [root@ localhlost ~]# grep '^[a-z]ae' /etc/passwd   //筛选ae的开始位置前面是小写字母的行
    [root@ localhlost ~]# grep '[a-z]ae' /etc/passwd   //筛选ae的前面是小写字母的行
    

    值得注意的是“*”号,在通配符中表示任意字符,而在正则表达式中表示匹配里面的子表达式0次或者多次,例如:

    [root@localhost ~]# grep 0* /etc/passwd
    这里0*会匹配所有内容(若是有空白行的文件,甚至包括空白行)[root@localhost ~]# grep 00* /etc/passwd
    这里00*匹配至少包含一个0的行(第一个0必须出现,第二个0可以出现0次或多次)
    4.egrep工具

    【例】/etc/passwd 文件为例,介绍扩展正则表达式。

    [root@localhost ~J]#egrep 0+ /etc/passwd	 	//匹配至少包含一个0的行
    [root@ localhost ~]# egrep '(root|ntp)' /etc/passwd 	//匹配包含root或ntp的行
    [root@localhost ~]# egrep ro?t /etc/passwd			//匹配rt或者rot的行
    [root@localhost ~]# egrep -v '^$|^#' /etc/passwd	//过滤文件中的空白行与#开头的行
    

    以上就是正则表达式的基本用法,只要正确运用,能够在字符串提取和文本修改中起到很大作用。

    二、Sed工具概述

    1.sed基本语法- [地址 1][地址2]操作[参数]
    命令语法:
    sed -e '编辑指令' 文件1 文件2...
    sed -n -e '编辑指令' 文件1 文件2...
    sed -i -e '编辑指令' 文件1 文件2....
    
    常用选项:
    -e	指定要执行的命令,只有一个编辑命令时可省略。
    -n	只输出处理后的行,读入时不显示。
    -i	直接编辑文件,而不输出结果。
    
    编辑指令格式: [地址 1][地址2]操作[参数]

    **地址:**正则表达式,数字或$,如果没有地址代表所有的行

    参数:-般用g代表只要符合条件,全部都进行处理

    操作:

    P	输出指定的行  6p代表6行
    d	删除指定的行
    S	字串替换,格式:“行范围s/旧字符串|新字符串/g”
    r	读取指定文件,支持扩展的正则表达式
    w	保存为文件
    i	插入,在当前行前面插入一行或多行
    a	插入,在当前行后面插入 
    q	退出 
    p;n 奇数行
    n;p 偶数行
    
    2.Sed用法示例
    (1)输出指定的行
    # sed -n 'p' /etc/passwd			//将所有内容输出
    # sed -n '6p' /etc/passwd			//将第6行内容输出
    # sed -n '6, 8p' /etc/passwd		//将第6 ~ 8行内容输出
    # sed -n 'p;n' /etc/passwd			//将所有奇数行输出
    # sed -n 'n;p' /etc/passwd			//将所有偶数行输出
    # sed -n '1,10{p;n}' /etc/passwd 	//将 1 ~ 10行中的奇数行输出
    # sed -n '1,10{n;p}' /etc/passwd 	//将 1 ~ 10行中的偶数行输出
    # sed -n '10,${n;p}' /etc/passwd 	//将第10行到末尾之间的奇数行输出
    # sed -n '$p' /etc/passwd			//将最后一行输出
    # sed -n '1,+4p' /etc/passwd		//将第1行开始,连续4行进行输出(1~5行)
    # sed -n '/root/p' /etc/passwd    //将匹配包含root 的行进行输出
    # sed -n '10,/nom/p' /etc/passwd 	 //将从第10行至第一个包含nom的行进行输出
    # sed -nr '/ro{1,}t/p' /etc/passwd 	 //匹配不少于1次前导字符o,加-r参数支持扩展正则表达式
    # sed -n '/root\|ntp/p' /etc/passwd //输出包含root或者ntp 的行
    

    注意,如果遇到特殊符号的情况,拓展正则还需要转义字符”\”

    # sed -n '/nom/=' /etc/passwd			//将包含nom所在的行行号输出,"=” 号
    # sed -e '5q' /etc/passwd				//输出前5行信息后退出,q退出
    # sed -e '=' -e 's/^/5q/g' /etc/passwd  //输出前5行信息并输出行号后退出,q退出
    
    (2)插入符合条件的行
    # sed '/root/i admin:x:490:490::/:/sbin/nologin' /etc/passwd
    //在含有root行的前面一行添加admin:x:490:490:/:/sbin/nologin
    
    # sed '/root/a admin:x:490:490::/:/sbin/nologin' /etc/passwd
    //在含有root行的下一行添加 admin ,a表示在当前行的后面行添加 
    
    # sed '3aADMIN' /etc/passwd	
    //在第3行之后插入ADMIN
    
    其中使用插入时,如果添加多行数据,除最后一行外,每行末尾都需要用“\n”
    符号表示数据未完结,换行。
    # sed '3aADMIN\nuuu\n99999' /etc/passwd
    
    (3)删除符合要求的行
    # sed '1d' /etc/passwd 		  //删除第1行
    # sed '$d' /etc/passwd			//删除最后1行
    # sed '/^$/d' /etc/passwd		//删除所有空行
    # sed '2,4d' /etc/passwd		   //删除第2~4 行
    # sed '/root/d' /etc/passwd		//删除含有root的行
    # sed '/root/!d' /etc/passwd	   //删除不包含root的行,这里的“!”号表示取反操作
    # sed '/^root/d' /etc/passwd	   //删除以root开头的行
    # sed '/nologin$/d' /etc/passwd	//删除以nologin结尾的行
    
    (4)替换符合条件的文本
    # sed 's/root//g' /etc/passwd	//将文件中所有的root都删除
    # sed '/root/c admin:x:490:490::/:/sbin/nologin' /etc/passwd
    //将含有root的行替换为admin:x:490:49/:/:/sbin/nologin
    
    # sed -n 's/root/admin/2p' /etc/passwd //把每行的第2个root替换成admin
    # sed '/root/s/root/ROOT/g' /etc/passwd	//将包含root的所有行中的root都替换为ROOT
    # sed '1,3s/bin/BIN/g' /etc/passwd 		//将第1~ 3行中的所有bin都督换为BIN
    # sed 's/$/ABC/' /etc/passwd			//在每行行尾插入字符串ABC
    # sed '5s/$/ABC/' 1.txt           //在第5行行尾插入字符串ABC
    # sed '3s/A/000/g' 1.txt         //将第3行的A替换成000
    # sed 's/^/#/' /etc/passwd				//在每行行首插入#号
    # sed '1,5s/^/#/' 1.txt       //在1到5行插入#号
    # sed '/root/s/^/#/' /etc/passwd 		//将包含root的行的行首插入#号
    #root:x:0:0:root:/root:/bin/bash
    # sed '1cABC' /etc/passwd				//将第一行替换为ABC
    # sed 'y/root/ROOT/' /etc/passwd		//将root对应替换为ROOT,y表示对应替换
    # sed '1,10y/root/ROOT/' /etc/passwd	   //将第 1-10行中的 root对应替换为 ROOT
    
    (5)迁移符合条件的文本
    [root@localhost ~]# sed '/root/w file1' /etc/passwd 		//将包含root的行另存为文件file1
    [root@localhost ~]# sed '/root/{H;d};$G' /etc/passwd		//将包含root的行迁移至未尾
    [root@localhost ~]# sed '1, 5{H;d};$G' /etc/passwd			//将第1~ 5行内容迁移至未尾
    [root@localhost ~]# sed '/root/{H;d);$G' /etc/passwsd		//将包含root的行迁移至末尾
    
    其中h表示保存当前模式到一个缓冲区,G表示取出保存的模式
    
    (6)执行多次命令
    [root@localhost ~]# sed -ne ‘s/root/admin/' -ne 's/bash/sh/p’ /etc/passwd //将root和bash行作替换
    
    注意:-e可以将多个命令连接起来,也可将多个编辑命令保存到文件中,通过-f指定文件,已完成多个处理操作。
    
    (7)直接修改文件内容
    # sed -i 's/^/#/' /etc/passwd		//在每行开头插入#号,直接修改原文件
    # sed -i 's/^#//g' /etc/passwd		//将每行开头的#号删除,直接修改原文件
    
    3.Sed脚本应用案例

    调整vsftpd服务的配置文件,实现禁止匿名用户登录,允许本地用户登录并且具有写入权限。

    #!/bin/bash
    #设置变量,指定配置文件路径
    CONFIG=" "
    #源配置文件备份
    [ -e "$CONFIG.old" ] || cp $CONFIG $CONFIG.old
    #修改配置文件,实现禁止匿名用户登录
    sed -i ‘/^anonymous_enable/s/YES/NO/g' $CONFIG
    #允许本地用户登录,且具有写入权限
    sed -i -e '/^local_enable/s/NO/YES/g' -e '/^write_enable/s/NO/YES/g' $CONFIG
    #监听端口
    sed -i '/^listen/s/NO/YES/g' $CONFIG
    

    任务一:

    一键安装ftp,不允许匿名用户访问。配置系统用户student访问指定目录/mnt/pub,并且对/mnt/pub/FTP这个目录具有上传、新建、删除的权限,系统用户stu1只具有下载的权限,配置完成后,重启服务,并在客户端进行测试。

    编写思路:

    1.FTP配置文件的配置项
    
    12 anonymous_enable=YES  改为 NO   拒绝匿名用户访问
    
    16 local_enable=YES           允许系统用户访问
    
    19 write_enable=YES           允许写入
    
    20 local_root=/mnt/public/         指定FTP的主目录为/mnt/public
    
    21 chroot_local_user=YES         只允许系统用户访问指定的主目录
    
    22 allow_writeable_chroot=YES       允许写入
    
    2.判断/mnt/public目录是否存在,如果不存在则:mkdir /mnt/public/FTP
    
    3.新建两个用户:student  stu1 
    
    4.给student用户权限:chown student  /mnt/public/FTP
    
    5.判断是否安装?如果没有安装则:yum install vsftpd ftp -y
    
    6.修改配置文件:
    
    sed  -i ‘s/ anonymous_enable=YES/anonymous_enable=NO/g’  /etc/vsftpd/vsftpd.conf
    
    sed  -i ‘19alocal_root=/mnt/public/\nchroot_local_user=YES\nallow_writeable_chroot=YES’  /etc/vsftpd/vsftpd.conf
    

    7.启动服务

    三、awk工具介绍

    Awk是一个功能强大的编辑工具,用于在Linux/UNIX下对文本和数据进行处理。数据可以来自一个或多个文件,也可以为其他命令的输出,常作为脚本来使用。在执行操作时,Awk逐行读取文本,默认以空格为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,对比该行是否与给定的模式相匹配,并按模式或者条件执行编辑命令,也可从脚本中调用编辑指令过滤输出相应内容。

    1.Awk基本语法
    Awk的两种语法格式:
    awk[选项] '模式或条件 {编辑指令}' 文件1文件2
    
    awk -f 脚本文件 文件1文件2
    

    在Awk语句中,模式部分决定何时对数据进行操作,若省略则后续动作时刻保持执行状态,模式可以为条件语句、复合语句或正则表达式等。每条编辑指令可以包含多条语句,多条语句之间要使用分号或者空格分隔的多个区域。常用选项F定义字段分隔符,默认以空格或者制表符作为分隔符。

    Awk提供了很多内置变量,经常用于处理文本,了解这些内置变量的使用是很有必要的。

    FS	指定每行文本的字段分隔符,缺省为空格或制表位
    NF	当前处理的行的字段个数
    NR	当前处理的行的行号(序数)
    $o	当前处理的行的整行内容
    Sn	当前处理行的第n个字段(第n列) 
    

    在Awk中,缺省的情况下总是将文本文件中的一行视为一个记录,而将一行中的某一部分作为记录中的一个字段。为了操作这些不同的字段,Awk借用Shell的方法,用1,2,3… 这样的方式来顺序地表示行(记录)中的不同字段。例如:

    # awk -F: '{print $0,NF}' /etc/passwd
    输出以冒号为分隔的/etc/passwd文件中记录的字段,共7个字段,$1、$2、$3...$7.
    $0指当前处理的行的整行内容,换句话说也就是输出所有内容
    

    【例】截取指定的列

    用Awk截取命令df -Th输出的结果,不带任何条件(也就是执行所有内容) ,进行格式化输出,打印第1列和第6列数据。
    
    # df -Th|awk '{print $1,$6}'
    

    特殊的,$0指当前处理的行的整行内容,换句话说也就是输出所有内容,那么

    # awk '{print $0}' /etc/passwd
    相当于
    # cat /etc/passwd
    
    2.Awk用法示例
    (1)打印文本内容
    # awk '/^root/{print}' /etc/passwd” 		//输出以root开头的行
    # awk '/nologin$/{print}' /etc/passwd		//输出以nologin结尾的行
    # awk -F ":" '/bash$/{print | "wc -l"}' /etc/passwd
    //统计可登录系统用户的个数。使用管道符调用命令wc -|统计使用bash 的用户个数即为可以
    //登录系统用户的个数
    

    在使用Awk的过程中,可以使用关系运算符作为“条件”,用于比较数字与字符串,运算符有大于(>)、小于(<)、大于等于(>=) 、小于等于(<=)、等于(==)、不等于(!=)这些;也可以使用逻辑操作符&&,表示“与”,||表示“或”,!表示“非”;还可以进行简单的数学运算加(+)、减(-)、乘(*)、除(/)、取余(%)、乘方(^)。只有当条件为真,才执行指定的动作。

    # awk 'NR==1,NR= 3 {print)' /etc/passwd 	 //输出第1行至第3行内容
    # awk 'NR== 1||NR-3 {print)' /etc/passwd	//输出第1、3行内容
    # awk '(NR>=1)&&(NR<=3){print}' /etc/passwd  //输出第 1行到第3行内容
    # awk ‘(NR%2)==1 {print}' /etc/passwd 		//输出所有奇数行的内容
    # awk ‘(NR%2)==0 {print}' /etc/passwd 		//输出所有偶数行的内容
    # awk -F “:” ‘!($3 < 900 )’ /etc/passwd	//输出第3个字段不小于900的行“!”号表示取反
    

    在使用Awk过程中还可以使用条件表达式,条件表达式的运算涉及两个符号,冒号和问号,其实质就是if…else语句的捷径,有着和if…else相同的结果。

    # awk -F: '{if($3>200) {print $0}}' /etc/passwd //输出第3个字段大于200的行
    # awk -F: '{max=($3>$4)? $3:$4; print max}' /etc/passwd
    //如果第3个字段的值大于第4个字段的值,则把问号前表达式$3的值赋给max,否则就将冒号后那个表达式的值赋给max
    
    # awk -F: ‘{max =($3>200)? $3:$1; print max}’ /etc/passwd
    //如果第3个字段的值大于200,则把第3个字段的值赋给max,否则就将第1个字段的值赋给max
    
    (2) 按字段输出文本
    #awk -F: '{print NR, $0}' /etc/passwd
    //输出处理数据的行号,每处理完一条记录,NR值加1
    1 root:x:0:0:root:/root:/bin/bash
    2 bin:x:1:1:bin:/bin:/sbin/nologin
    3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    …
    # echo "you-me-he" | awk -F '[-]' '{print $NF}'
    # awk -F ":" '$3<5{print $1,$3}' /etc/passwd	//输出第3列小于5的第1列与第3列数据
    # awk -F ":" '($1~"root")&&(NF=7){print $1,$2}' /etc/passwd
    //输出包含7个字段,并且第1个字段中包含root的行的第1与第2个字段内容
    
    # awk -F “:” ‘NR==3,NR==7 {print $1,$7}’ /etc/passwd
    //输出第3行到第7行中以冒号为分隔符的第1列与第7列数据
    
    需要的话,输出数据时还可以插入一些文本标签:
    # awk -F “:” ‘NR==3,NR==7 {print “USERNAME:” $1,”SHELL:” $7}’ /etc/passwd
    # awk -F: '/^root/{print "hi:"$1}' /etc/passwd
    # awk -F: '$7~"/bash"{print $1}' /etc/passwd
    # awk -F’:’ ‘{print $1“:”$2”:”$3”:”$4}’ /etc/passwd
    //保留原来的格式,输出以冒号为分割。/etc/passwd文件的前4个字段
    # awk -F “:” ‘{print $1,$3}’ /etc/passwd
    //输出以冒号为分隔符的第1列和第3列数据
    

    或者

    # awk ‘BEGIN {FS=”:”} {print $1,$3}’ /etc/passwd
    //在FS之前加一个BEGIN(注意是大写),当读取第一条数据之前,先把分隔符加上后再进去操作。相似的还有END,在所有数据处理完毕后执行。
    
    # awk ‘BEGIN {X=0};/\/bin\/bash$/{x++};END{printx}‘ /etc/passwd
    //统计以/bin/bash为结尾的行数
    
    AWK执行顺序就是这样的:首先执行BEGIN{ }中的操作;然后从指定文件中逐行读取数据,自动更新NF、NR、$0、$1等内建变量的值,去s执行‘模式或条件{编辑指令}‘;最后执行END{ }中的后续操作。
    
    (3)处理命令输出的结果

    AWK也可以利用管道符“ | ”处理命令结果。

    # date | awk '{print "Month:"$2"\nYear:"$1}'
    	Month:03月
    	Year:CST
    
    3.AWK应用案例

    ​ 本脚本用来实现对磁盘空间的监控,当磁盘的使用空间超过90%则发E-mail报警。

    #!bin/bash
    #monitor available disk space
    #截取以“/”为结尾的行,打印出第5个字段也就是跟分区使用百分比,截取掉“%”
    SPACE=df | sed -ne'/\/$/ p' | awk '{print $5}' | sed 's/%//'
         //
    #截取出的数据与90进行相比,大于90给管理员发邮件报警
    if [ $SPACE -ge 90 ]
    then
    echo “Disk spaceis not enough” | mail -s “Disk Alarm”admin@example.com
    fi
    

    四、Shell编程实战

    1.例:系统概况
    (1) 需求描述

    为root用户编写登陆欢迎脚本,成功登陆后报告当前主机中的进程数,已登录用户数、登录的用户名、根文件系统的磁盘使用率

    (2) 实现步骤
    1) 新建脚本文件welcome.sh,用来输出各种监控信息。
    [root@localhost ~]# vim /root/welcome.sh
        #!/bin/bash
        #此脚本用于显示进程数,登录的用户与用户名,根分区的磁盘使用率
        echo “已开启进程数:$(($(ps aux | wc -l)-l))”	#注意要减1
        echo “已登录用户数:$(who | wc -l)”
        echo “已登录的用户账号:$(who | awk ‘{print $1})”
        echo “根分区磁盘使用率:$(df -h | grep “/$” | awk ‘{print $5})[root@localhost ~]# chmod +x /root/welcome.sh
    
    2) 修改/root/.bash_profile文件,调用welcome.sh脚本程序
    [root@localhost ~]# vim /root/.bash_profile
    ……	//省略部分内容
    /root/welcome.sh
    
    3) 使用root用户重新登录,验证欢迎脚本的输出信息
    
    2.例:MAC记录与端口扫描脚本
    (1) 需求描述

    ● 编写名为system.sh的脚本,记录局域网中各主机的MAC地址,保存到/etc/ethers文件中;若此文件已存在,应先转移进行备份;每行一条记录,第1列为IP地址,第2列为对应的MAC地址。

    ● 检查有哪些主机开启了匿名FTP服务,扫描对象为/etc/ethers文件中的所有IP地址,扫描的端口为21.

    (2) 实现步骤
    [root@localhost ~]#vim system.sh
        #!/bin/bash
        #定义网段地址、mac列表文件
        NADD=192.168.4.”
        FILE=/etc/ethers”
        #发送ARP请求,并记录反馈信息
        [ -f $FILE ] && /bin/cp -f $FILE $FILE.old		#备份原有文件
        HADD=1		#定义起始扫描地址
        while [ $HADD -lt 254 ]
        do
            arping -c 2 -w 1 ${NADD}${HADD} &> /dev/null
            if [ $? -eq 0 ];then
            	arp -n grep ${NADD}${HADD} | awk ‘{print $1,$3}>> $FILE
            fi
            let HADD++
        done
        TARGET=$(awk ‘{print $1}/etc/ethers)
        echo “以下主机已开放匿名FTP服务:”
        for IP in $TARGET
        do
            wget [ftp://$IP/](ftp://$IP/) &> /dev/null
            if [ $? -eq 0 ];then
            	echo $IP
            	rm -rf index.html  #事先在ftp服务器上准备下载文件,测试后删除				
            fi
        done
    # chmod +x system.sh
    #./system.sh		#执行检测程序
    #cat /etc/ethers  #确认记录结果
    
    3.例:开发系统监控脚本
    (1) 需求描述

    编写名为sysmon.sh的shell监控脚本

    监控内容包括CPU使用率、内存使用率、根分区磁盘占用率

    百分比只需精确到个位,如7%、12%、23%等

    出现以下任一情况时告警:磁盘占用率超过90%、CPU使用率超过80%、内存使用率超过90%,告警邮件通过mail命令发送到指定邮箱

    结合crond服务,每半小时执行一次监控脚本

    (2) 实现步骤
    1) 编写Shell监控脚本
    [root@localhost ~]# vim /root/sysmom.sh
    #!/bin/bash
    #提取性能监控指标(磁盘占用、CPU使用、内存使用)
    DUG=$(df -h | grep “/$” | awk ‘{print $5}| awk -F%{print $1})
    CUG=$(expr 100 -$(mpstat | tail -l | awk ‘{print $12}| awk -F.{print $1}))
    MUG=$(expr $(free | grep “cache:| awk ‘{print $3})\* 100/ $(free | grep “Mem:| awk ‘{print $2}))
    #设置告警日志文件、告警邮箱
    ALOG=/tmp/alert.txt”
    AMAIL=”root@localhost”
    #判断是否记录告警
    if [ $DUG -gt 90 ]
    then
    	echo “磁盘占用率:$DUG%>> $ALOG
    fi
    if [ $CUG -gt 80 ]
    then
    	echo “CPU使用率:$CUG%>> $ALOG
    fi
    if [ $MUG -gt 90 ]
    then
    	echo “内存使用率:$MUG%>> $ALOG
    fi
    #判断是否发送告警邮件,最后删除告警日志文件
    if [ -f $ALOG ] 
    then
    	cat $ALOG | mail -s “Host Alert” $AMAIL
    	rm -rf $ALOG
    fi
    [root@localhost ~]# chmod +x /root/sysmom.sh
    
    2) 测试sysmon.sh脚本的执行情况
    首先确认有可用的邮件服务器(如postfix,sendmail等),然后调低监控阈值,执行sysmon.sh脚本进行测试。
    [root@localhost ~]# /root/sysmon.sh
    然后查收root@localhost的邮箱,确认告警邮件内容。
    [root@localhost ~]# mail
    
    3) 设置crontab计划任务
    首先确认系统服务crond已经运行
    [root@localhost ~]# /etc/init.d/crond status
    crond (pid 5839)正在运行…
    然后添加crontab计划任务配置,每半小时调用一次sysmon.sh脚本程序
    [root@localhost ~]# crontab -e
    */30 * * * * /root/sysmon.sh
    
    展开全文
  • 要保护自己编写shell脚本程序,方法有很多,最简单的方法有两种:1、加密 2、设定过期时间,下面以shc工具为例说明: 一、安装shc工具   shc是一个加密shell脚本的工具.它的作用是把shell脚本转换为一个可执行...

    要保护自己编写的shell脚本程序,方法有很多,最简单的方法有两种:1、加密 2、设定过期时间,下面以shc工具为例说明:
    一、安装shc工具
     
    shc是一个加密shell脚本的工具.它的作用是把shell脚本转换为一个可执行的二进制文件.

    shc官方网站:
    http://www.datsi.fi.upm.es/~frosal/

     

    shc的下载地址:            
    linux/shc-3.8.tgz">http://www.datsi.fi.upm.es/%7Efrosal/sources/shc-3.8.6.tgz

    安装:
    tar zxvf shc-3.8.tgz
    cd shc-3.8
    make test
    make
    make test
    make strings
    make install  这一步需要root权限
     
    二、加密方法:
    shc -r -f script-name  注意:要有-r选项, -f 后跟要加密的脚本名.
    运行后会生成两个文件,script-name.x 和 script-name.x.c
    script-name.x是加密后的可执行的二进制文件.
    ./script-name    即可运行.
    script-name.x.c是生成script-name.x的原文件(c语言)
    三、设定期限:
    首先使用shc转化为二进制,并加上过期时间,如
    ./shc -e 12/06/2006 -m "please contact yazjiyao@yahoo.com.cn" -r -f flushvpn.sh
     
     我一般在程序中加入自动更新系统时间 的命令,防止用户更改系统时间。

    展开全文
  • Python教程本章将会教你如何编写、保存与运行 Python 程序。通过 Python 来运行的你的程序有两种方法——使用交互式解释器提示符或直接运行一个源代码文件。我们将了解如何使用他们二者的功能。使用解释器提示符在你...
  • 在java程序如何调用linux的命令?如何调用shell脚本呢?这里不得不提到java的process类了。process这个类是一个抽象类,封装了一个进程(你在调用linux的命令或者shell脚本就是为了执行一个在linux下执行的程序,...
  • 编写UNIX Shell程序考试

    2010-03-27 13:58:00
    赛迪网校继续教育学员编写UNIX Shell程序考试 1、在shell脚本中使用函数的优点是什么?下列哪项不是正确内容。bA、它们比单独的命令执行快 B、它们可执行递归代码 C、它们可存储以后在脚本中使用的值 D、它们把shell...
  • linux下如何编写shell脚本_2012-12-21

    万次阅读 2012-12-21 09:21:13
    因为我的同事cwl有事情请假两天,所以需要我直接和lenovo进行交涉,我需要些一个简单的测试程序,这里用到了编写shell脚本,实现两个c程序的编译。我对shell脚本的认识,除了执行过同事写的shell 脚本外,其他...
  • 编写Linux Shell脚本的最佳实践 由于工作需要,最近重新开始拾掇shell脚本。虽然绝大部分命令自己平时也经常使用,但是在写成脚本的时候总觉得写的很难看。而且当我在看其他人写的脚本的时候,总觉得难以阅读。毕竟...
  • 什么是shell以及如何编写最简单的shell此篇文章仅作为个人的学习笔记什么是shellshell是一种linux可以直接识别并执行的程序设计语言shell分类 sh(全称 Bourne Shell): 是UNIX最初使用的 shell,而且在每种 UNIX 上都...
  • 编写shell脚本

    2020-07-22 18:32:53
    这里写自定义目录标题ShellShell脚本功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants...
  • 编写shell脚本和执行

    2015-03-16 21:41:00
    这次的学习内容: 认识shell,如何编写shell脚本和执行Shell 其实就是一个解释执行命令的程序,所谓shell编程其实就是用一定的语法将各种基本的命令组合起来,让shell程序去解释执行。如果对windows的dos有了解,可以...
  • Shell既是一种命令语言,又是一种程序设计语言。作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。 shell语言...
  • 不知如何编写shell程序,makefile也是很糟糕,于是查找资料,自己编写一个最入门的例子。 程序文件为helloword.c makefile也很简单 test为shell程序 这三个文件放在/home/scs/helloword目录下 代码如下所示: ...
  • 使用 Python 编写 Spark 交互程序:1. 启动 Spark Shell在spark-shell中,已经创建了一个名为 sc 的 SparkContext 对象./bin/spark-shell --master local[4] --jars testcode.py--master 用来设置 context 将要连接...
  • 我最近开始使用Test Driven Design方法,不幸的是我不知道如何单元测试放入交互式shell的应用程序。这是我想要做的事情的基本概念:# peekaboo.pyfrom IPython import embedfrom IPython.config.loader import ...
  • 编写shell命令实现IOS的自动打包

    千次阅读 2016-06-01 11:00:07
    1.1如何创建shell程序 首先,推荐大家一个mac系统的文本编辑软件Sublime Text,可以提高我们编写shell指令的效率。 Mac环境下,如何创建shell脚本?下面,我们以 桌面上创建一个名为 hello 的shell脚本 为例子 ,...
  • 一、使用Python自身提供的交互式解释器在Linux、Windows、Mac OS的命令行窗口或Shell窗口,执行python命令,启动Python交互式解释器。交互式解释器会等待用户输入Python语句。输入Python语句并回车,解释器会执行...
  • Shell本身是一个用C语言编写程序,它是用户使用Linux的桥梁。 Shell既是一种命令语言,又是一种程序设计语言。作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并...
  • 1.shell如何运行程序的?shell由下面的循环组成:while (!end_of_input) getcommand execute command wait for command to finish我们可以实际用一下shell:jiange@jiange-Inspiron:~/cpp$ ls override ...
  • Shell本身是一个用C语言编写程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言。作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并...
  • 一、使用Python自身提供的交互式解释器在Linux、Windows、Mac OS的命令行窗口或Shell窗口,执行python命令,启动Python交互式解释器。交互式解释器会等待用户输入Python语句。输入Python语句并回车,解释器会执行...
  • shell是一个命令行解释器,它为用户提供了一个向Linux内核发送请求以便于运行程序的界面系统级程序,用户可以用shell来启动,挂起,停止甚至是编写一些程序shell还是一个功能强大的编程语言,易编写,易调试。...
  • 在Android应用程序中执行shell脚本可以省去一大堆繁琐的代码,还可以避免不必要的错误; 比如:拷贝文件夹时,可以执行shell命令中的 cp 命令达到目的;而在代码中实现拷贝文件夹时,不仅需要编写一大堆繁琐的代码,...
  • 总结来说,Shell是一个命令解释器,它通过接受用户输入的Shell命令来启动、暂停、停止程序的运行或对计算机进行控制。 shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、
  • 如何编写一个优雅的Shell脚本(一)

    千次阅读 2018-11-04 08:43:43
     shell脚本是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,本文简述如何编写一个优雅的shell脚本。 使用技术介绍 eval命令  可以将一个字符串当作一个命令执行。 CMD="ls -ltr"...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 576
精华内容 230
关键字:

如何编写shell程序