0%

Shell脚本

一、shell脚本基础

(一)shell脚本

包含一些命令或声明,并符合一定格式的文本文件

(二)格式要求:首行shebang机制

​ #!/bin/bash

​ #!/usr/bin/python

(三)用途
  • 自动化常用命令
  • 执行系统管理和故障排除
  • 创建简单的应用程序
  • 处理文本或文件
(四)脚本的基本结构
#!SHEBANG
CONFIGURATION_VARIABLES
FUNCTION_DEFINITIONS
MAIN_CODE
(五)脚本调试

检测脚本中的语法错误:

bash -n /path/to/some_script

调试执行:

bash -n /path/to/some_script
(六)变量
1.强类型

变量不经过强制转换,它永远是这个数据类型,不允许隐式的类型转换。一般定义变量时必须指定类型、参与运算必须符合类型要求;调用未声明变量会产生错误。如:Java,C#

2.弱类型

语言的运行时会隐式做数据类型转换。无需指定类型,默认均为字符型;参与运算会自动进行隐式类型转换;变量无需事先定义可直接调用。如:bash不支持浮点数,PHP

(七)bash中变量的种类
1.局部变量

生效范围为当前shell进程;对当前shell之外的其他shell进程,包括当前shell的子shell进程均无效

  • 变量赋值:name=’value’
  • 可以使用引用value:
    (1)可以直接字串:name=”root”
    (2)变量引用:name=”$USER”
    (3)命令引用:name=`COMMAND` name=$(COMMAND)
  • 变量引用:${name} $name
  • 显示已定义的所有变量:set
  • 删除变量:unset name
2.环境(全局)变量

生效范围为当前shell进程及其子进程

  • 变量声明、赋值:
    export name=VALUE
    declare -x name=VALUE
  • 变量引用:$name,${name}
  • 显示所有环境变量:env;printenv;export;declare -x
  • 删除变量:unset name
3.本地变量

生效范围为当前shell进程中某代码片段,通常指函数

4.位置变量

$1,$2……来表示,用于让脚本在脚本代码中调用命令行传递给它的参数

5.特殊变量

$? $0 $* $@ $# $$

(八)退出状态

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

  • 0代表成功,1-255代表失败
  • $? 变量保存最近的命令退出状态
例如:
ping -c1 -W1 hostdown &> /dev/null
echo $?
(九)条件测试
  • 判断某需求是否满足,需要由测试机制来实现
  • 评估布尔声明,以便用在条件性执行中
    • 若真,则返回0
    • 若假,则返回1
  • 测试命令
    • test EXPRESSION
    • [ EXPRESSION ]
    • [[ EXPRESSION ]]
      • 注意:EXPRESSION前后必须有空白字符
例如:
[root@localhost ~]# m=10
[root@localhost ~]# n=20
[root@localhost ~]# test $m -eq $n
[root@localhost ~]# echo $?
1
(十)使用read命令来接收输入

使用read来把输入值分配给一个或多个shell变量

  • -p 指定要显示的提示
  • -s 静默输入,一般用于密码
  • -n N指定输入的字符长度N
  • -d ‘字符’输入结束符
  • -t N TIMEOUT为N秒
(十一)条件选择if语句
  • 单分支

    if  判断条件;then 
                条件为真的分支代码
    fi
    
  • 双分支

    if  判断条件;then 
                条件为真的分支代码
    else
                条件为假的分支代码
    fi
    
(十二)条件判断:case语句
case变量引用in
        PAT1)
                    分支1
                    ;;
        *)
                    默认分支
                    ;;
        esac
(十三)循环
1.for循环
for 变量名 in 列表; do
    循环体
done
#例如:求100以为奇数之和
sum=0;for number in `seq 1 2 100`;do let sum+=number;done;echo "sum is $sum"
sum is 2500
#或者
for((sum=0,i=1;i<=100;i+=2));do 2500 let sum+="i;done;echo" "sum is $sum" sum < code>
2.while循环
while CONDITION;do
        循环体
done
#例:
sum=0;i=1;while [ "$i" -le 100 ];do let sum+=i;let i+=2;done;echo "sum is $sum"
sum is 2500
3.until循环
until CONDITION;do
        循环体
done
(十四)数组
  1. 声明数组:declare -a ARRAY_NAME
                    declare -A ARRAY_NAME:关联数组
    
    注意:两者不可相互转换
  2. 引用数组元素:${ARRAY_NAME[INDEX]}
    注意:省略[INDEX]表示引用下标为0的元素
  3. 引用数组所有元素:${ARRAY_NAME[*]}
                                   ${ARRAY_NAME[@]}
    
  4. 删除数组中的某元素:导致稀疏格式
    unset ARRAY[INDEX]
  5. 删除整个数组:unset ARRAY

二、自动生成脚本开头注释

在/root/目录下新建文件并命名成 “ .vimrc ” 名称,并添加以下模板代码

[root@localhost ~]# vim .vimrc
set ignorecase
set cursorline
set autoindent
autocmd BufNewFile *.sh exec ":call SetTitle()"
func SetTitle()
        if expand("%:e") == 'sh'
                call setline(1,"#!/bin/bash")
                call setline(2,"#*************************************************************")
                call setline(3,"#Author: Y*Y")                    
                call setline(4,"#Date:  ".strftime("%Y-%m-%d"))
                call setline(5,"#FileName:      ".expand("%"))
                call setline(6,"#*************************************************************")
                call setline(7,"")
        endif
endfunc                                                            
 autocmd BufNewFile * normal G

再建立shell脚本时则会自动添加开头注释为

[root@localhost ~]# vim choose.sh
#!/bin/bash
#*************************************************************
#Author: Y*Y
#Date:  2020-03-12
#FileName:      choose.sh
#*************************************************************

三、脚本示例

(一)脚本要求:当磁盘占用率达到80%以上时报警
[root@localhost ~]# vim checkspace.sh 
#!/bin/bash
#author:yy
#function:chechspace
value=df -h | awk '/^\/dev\/sda/{print $5}' | awk -F '%' '{print $1}' | sort -nr |head -1
[ $value -gt 80 ] && wall "disk will be full" || wall "disk is normal"

运行脚本

[root@localhost ~]# chmod +x *
[root@localhost ~]# ./checkspace.sh
Broadcast message from root@localhost.localdomain (pts/0) (Thu Mar 12 13:13:32 2020):

disk is normal
(二)交互示例:选择是或否
[root@localhost ~]# vim choose.sh
#!/bin/bash
#*************************************************************
#Author: Y*Y
#Date:  2020-03-12
#FileName:      choose.sh
#*************************************************************
read -p "Do you agree? yes or no:" answer
[[ $answer =~ ^([yY][Ee][sS])|[Yy]$ ]] && echo "GO!" || echo "NO"

运行脚本

[root@localhost ~]# chmod +x choose.sh
[root@localhost ~]# ./choose.sh
Do you agree? yes or no:yes
GO!
(三)调用函数实现IP地址是否合法
  1. 建立一个专门存放函数的文件
[root@localhost ~]# vim functions
checkip() {
    [[ "$1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] && echo "This is a IP" || echo "This is not IP"
}
  1. 新建shell脚本,调用函数
[root@localhost ~]# vim iptest.sh
#!/bin/bash
#*************************************************************
#Author: Y*Y
#Date:  2020-03-12
#FileName:      iptest.sh
#*************************************************************
. functions
read -p "Please input a ip addr: " ipaddr
checkip $ipaddr
  1. 运行脚本测试
[root@localhost ~]# chmod +x iptest.sh
[root@localhost ~]# ./iptest.sh 
Please input a ip addr: 1.1.1.1
This is a IP
(四)定义数组,数组中元素是/var/log目录下所有以.log结尾的文件,统计出其下标为计数的文件中的行数之和
declare -a files
files=(/var/log/*.log)
declare -i lines=0
for i in $(seq 0 $[${#files[*]}-1]); do
        if [ $[$i%2] -ne 0 ]; then                                
                let lines+=$(wc -l ${files[$i]} | cut -d' ' -f1)
        fi
done
echo "Lines: $lines."

运行结果

[root@localhost ~]# ./array.sh 
Lines: 70.