• shell编程


    shell编程

    shell编程能做什么

    1)安装操作系统(手动安全ISO) 自动化安装(kickstart cobbler)shell脚本
    2)初始化操作系统 优化(SSH优化、关闭SElinux、优化防火墙、NTP时间同步、更改默认YUM、源字符集、安装常用的软件 lrzsz net-tools tree.. wget、隐藏版本信息、加大文件描述符、内核优化...)初始化写入脚本 自动化执行
    3) 安装服务(Nginx PHP MySQL MariaDB NFS sersync REDIS keepalived docker....zabbix)使用shell脚本自动选择安装
    4) 启动----停止(centos6.x: /etc/init.d/server start;centos7.x:systemctl start server) 系统默认的启动方式 shell脚本
    5) 监控 zabbix、cacti、nagios、ELK、公司研发的监控平台;监控的值(shell脚本统计)
    6) 日志统计 三剑客 日志切割(脚本+定时任务)

    初识Shell

    什么是shell

    pwd ls 都是通过bash解释的、Shell是一个命令解释器,作用是解释执行用户输入的命令及程序
    交互式模式就是shell等待你的输入,并且执行你提交的命令。这种模式被称作交互式是因为shell与用户进行交互。这种模式也是大多数用户非常熟悉的:登录、执行一些命令、签退。当你签退后,shell也终止了。shell也可以运行在另外一种模式:非交互式模式。在这种模式下,shell不与你进行交互,而是读取存放在文件中的命令,并且执行它们。当它读到文件的结尾,shell也就终止了。

    什么是shell脚本

    命令的大礼包 把可执行命令放到文件中 称为shell脚本(判断语句 循环语句 数组....)
    编译语言: 把代码编程成二进制语言 机器可识别 一次编译 终身运行 速度快
    脚本语言: 每次执行脚本 一行行的解释

    shell的书写规范

    1. shell脚本存放统一的目录
    2. 脚本名字的结尾使用.sh
    3. 脚本的开头 必须有解释器 #!/bin/bash
    4. 脚本内有作者信息 脚本信息
    5. 每段代码块有注释(尽量使用英文)
    6. 标点符号 (语法尽量一次性书写完毕)
    7. 成对的符号 一次性书写完毕

    第一个shell脚本

    [root@test scripts]# vim hello.sh
    #!/bin/bash
    echo "Hello Word!"
    [root@test scripts]# 
     #执行脚本的三种方法
     #方法1 直接使用解释器执行
    [root@test scripts]# bash hello.sh 
    Hello Word!
    [root@test scripts]# 
    #方法2 全路径方式执行 需要执行权限
    [root@test scripts]# chmod +x hello.sh 
    [root@test scripts]# ./hello.sh 
    Hello Word!
    [root@test scripts]# 
    #方法3 source .执行脚本  子shell中的内容调用到父shell中执行
    [root@test scripts]# source hello.sh 
    Hello Word!
    [root@test scripts]# . hello.sh 
    Hello Word!
    [root@test scripts]# 
    

    环境变量

    什么是环境变量?

    LANG='en_US.UTF-8'
    name=test
    右边一堆内容 使用一个名字来代替称为环境变量
    如何查看变量环境变量 加$
    echo $name
    env 查看系统定义的环境变量

    变量的分类

    全局变量(环境变量) 针对系统所有用户生效
    局部变量(普通变量) 针对当前登录用户生效

    变量生存周期分类 两类

    临时性 export 声明变量即可 或者 name=oldboy
    永久性 修改配置文件 /etc/profile

    #环境变量文件执行顺序
    1. /etc/profile
    2. .bash_profile
    3. .bashrc
    4. /etc/bashrc
    #如果按照文件内容的生效顺序
    1. /etc/profile
    2. .bashrc
    3. /etc/bashrc
    4. .bash_profile
    

    如何定义环境变量

    要求以字母 数字 和下划线组合  尽量以字母和_开头 等号两端不允许有空格 名字 见名知其意
    变量名字的定义的语法:
    OLDBOY_AGE=18  系统用的变量都是大写
    oldboy_age=18  全小写
    oldboy_Age=18  小驼峰语法
    Oldboy_Age=18  大驼峰语法
    变量值得定义:
    1.数字定义  连续的数字    test=188888
    2.字符串定义 连续的字符串 name="test test test" 不知道加什么就加双引号
    例子: CODE_DIR=/etc/sysconfig/network-scripts/
    [root@test scripts]# name=opesn
    [root@test scripts]# echo "$name"
    opesn
    [root@test scripts]# echo '$name'
    $name
    [root@test scripts]# 
    3.命令的定义
    方法1	[root@test scripts]# tim=`date +%F`
    方法2	[root@test scripts]# tim=$(date +%F)
    
    

    特殊的位置变量

    $0 代表了脚本的名称,如果使用全路径执行则脚本名称带全路径
    $n 代表脚本的第n个参数 $0被脚本名称占用 参数从$1开始 $9 以后需要加{}
    $# 代表脚本传参的总个数
    $* 获取脚本的所有的参数 不加双引号和$@相同 加上双引号则把参数视为一个整体 $1$2$3(在循环体中)
    $@ 获取脚本的所有的参数 不加双引号和$* 相同 加上双引号则把参数视为独立的(在循环体中)
    $? 获取上一条命令的结果 0为成功 非0失败 0-255之间
    $$ 获取脚本的PID
    $! 上一个在后台运行的脚本的PID 调试使用
    $_ 获取命令行或脚本的最后一个参数 相当于ESC .

    变量传参的三种方法

    方法1 直接传参
    方法2 赋值传参
    方法3 read传参
    #方法1
    [root@test scripts]# vim test.sh
    #!/bin/bash
    echo $1 $2
    [root@test scripts]# bash test.sh 1 2
    1 2
    [root@test scripts]# 
    #方法2
    [root@test scripts]# vim test.sh
    #!/bin/bash
    name1=$1
    name2=$2
    echo ${name1} ${name2}                
    [root@test scripts]# bash test.sh 1 2
    1 2
    [root@test scripts]#
    #方法3
    [root@test scripts]# bash test.sh
    please input name : 1
    please input name : 2
    1
    2
    [root@test scripts]# 
    
    #使用read方式更改主机名和IP地址
    [root@test scripts]# vim hostname_and_ip.sh
    #!/bin/bash
    eth=/etc/sysconfig/network-scripts/ifcfg-eth0
    read -p "please input hostname: " name
    hostnamectl set-hostname ${name}
    read -p "please input IP: " ipadd
    sed -i "/IPADDR/c IPADDR=${ipadd}" ${eth}                     
    [root@test scripts]# 
    [root@test scripts]# bash hostname_and_ip.sh 
    please input hostname: opesn
    please input IP: 10.0.1.250         
    [root@test scripts]# 
    
    

    变量的子串

    #计算变量的长度
    [root@test scripts]# echo $test|wc -L
    10
    [root@test scripts]# echo ${#test}
    10
    [root@test scripts]# expr length "$test"
    10
    [root@test scripts]# echo $test |awk '{print length}'
    10
    [root@test scripts]# 
    #截取变量中的字符
    [root@test scripts]# echo ${test:2:2}
    am
    [root@test scripts]# echo ${test:2}
    am opesn
    [root@test scripts]# echo ${test:2:4}
    am o
    [root@test scripts]# 
    

    变量子串的删除和替换

    #从前面往后面删除(##代表贪婪匹配)
    [root@test scripts]# url=www.baidu.com
    [root@test scripts]# echo ${url}
    www.baidu.com
    [root@test scripts]# echo ${url#*.}
    baidu.com
    [root@test scripts]# echo ${url#*.*.}
    com
    [root@test scripts]# echo ${url##*.}
    com
    [root@test scripts]# 
    
    #从后面往前面删除(%代表贪婪匹配)
    [root@test scripts]# url=www.baidu.com
    [root@test scripts]# echo ${url}
    www.baidu.com
    [root@test scripts]# echo ${url%.*}
    www.baidu
    [root@test scripts]# echo ${url%.*.*}
    www
    [root@test scripts]# echo ${url%%.*}
    www
    [root@test scripts]# 
    
    #替换(//代表贪婪匹配)
    [root@test scripts]# url=www.baidu.com
    [root@test scripts]# echo ${url}
    www.baidu.com
    [root@test scripts]# echo ${url/baidu/qq}
    www.qq.com
    [root@test scripts]# echo ${url/w/a}
    aww.baidu.com
    [root@test scripts]# echo ${url//w/a}
    aaa.baidu.com
    [root@test scripts]# 
    

    数值运算

    #expr只能做整数运算
    [root@test scripts]# expr 1 + 1
    2
    [root@test scripts]# expr 5 - 5
    0
    [root@test scripts]# expr 1 * 5
    5
    [root@test scripts]# expr 10 / 5
    2
    [root@test scripts]# 
    
    #$[]只能做整数运算
    [root@test scripts]# echo $[10+10]
    20
    [root@test scripts]# echo $[10-10]
    0
    [root@test scripts]# echo $[10*10]
    100
    [root@test scripts]# echo $[10/10]
    1
    [root@test scripts]# 
    
    #$(())只能做整数运算,效率最高的运算
    [root@test scripts]# echo $((5+5))
    10
    [root@test scripts]# echo $((5-5))
    0
    [root@test scripts]# echo $((5*5))
    25
    [root@test scripts]# echo $((5/5))
    1
    [root@test scripts]# 
    
    #let只能做整数运算
    [root@test scripts]# let sum=1+1
    [root@test scripts]# echo $sum
    2
    [root@test scripts]# 
    
    #bc整数、小数运算
    [root@test scripts]# echo 10+10|bc
    20
    [root@test scripts]# echo 10-10|bc
    0
    [root@test scripts]# echo 10*10|bc
    100
    [root@test scripts]# echo 10/10|bc
    1
    [root@test scripts]# 
    
    #awk小数、整数运算
    [root@test scripts]# awk 'BEGIN{print 10-5.5}'
    4.5
    [root@test scripts]# awk 'BEGIN{print 10+5.5}'
    15.5
    [root@test scripts]# awk 'BEGIN{print 10*5}'
    50
    [root@test scripts]# awk 'BEGIN{print 10/5}'
    2
    [root@test scripts]# 
    
    #python小数、整数运算
    [root@test scripts]# python
    >>> 10+5
    15
    >>> 10-2
    8
    >>> 5*5
    25
    >>> 5/5
    1
    >>> 
    
    #expr 判断传参是否为整数
    [root@test ~]# vim expr.sh
    #!/bin/bash
    num1=$1
    num2=$2
    expr $1 + $2 &>/dev/null
    [ $? -ne 0 ] && echo "请输入两个整数" && exit
    echo "${num1}+${num2}=$[${num1}+${num2}]"
    [root@test ~]# bash expr.sh 1 1.5
    请输入两个整数
    [root@test ~]# bash expr.sh 1 1
    1+1=2
    [root@test ~]# 
    

    条件表达式

    [ -f file ]
    -e 文件存在则为真
    -f 是否存在并且为普通文件
    -d 是否为目录
    -r 是否可读
    -w 是否可写
    -x 是否可执行
    
    [root@test ~]# [ -e /etc ] && echo "存在"||echo "不存在"
    存在
    [root@test ~]# [ -e /etcc ] && echo "存在"||echo "不存在"
    不存在
    [root@test ~]# [ -f /etc ] && echo "存在"||echo "不存在"
    不存在
    [root@test ~]# [ -f /etc/hosts ] && echo "存在"||echo "不存在"
    存在
    [root@test ~]# 
    
    

    数值表达式

    [ 整数1 比较符 整数2 ]
    -eq	等于
    -ne 不等于
    -gt 大于
    -ge 大于等于
    -lt 小于
    -le 小于等于
    
    [root@test ~]# [ 10 -eq 10 ] && echo "ok" ||echo "no"
    ok
    [root@test ~]# [ 10 -gt 10 ] && echo "ok" ||echo "no"
    no
    [root@test ~]# [ 10 -ge 10 ] && echo "ok" ||echo "no"
    ok
    [root@test ~]# [ 10 -lt 10 ] && echo "ok" ||echo "no"
    no
    [root@test ~]# [ 10 -le 10 ] && echo "ok" ||echo "no"
    ok
    [root@test ~]# [ 10 -ne 10 ] && echo "ok" ||echo "no"
    no
    [root@test ~]# 
    
    

    多整数比较

    [ 整数1 比较符 整数2 -o 整数3 比较符 整数4 ]
    [ 整数1 比较符 整数2 -a 整数3 比较符 整数4 ]
    -o	或
    -a	与
    [root@test ~]# [ 10 -eq 10 -o 10 -ne 10 ]
    [root@test ~]# echo $?
    0
    [root@test ~]# [ 10 -eq 10 -a 10 -ne 10 ]
    [root@test ~]# echo $?
    1
    [root@test ~]# 
    
    

    字符串比较

    #字符串比较必须加双引号
    [root@test ~]# [ "$USER" = root ]
    [root@test ~]# echo $?
    0
    [root@test ~]# [ "$USER" = "root" ]
    [root@test ~]# echo $?
    0
    [root@test ~]# [ "$USER" = "opesn" ]
    [root@test ~]# echo $?
    1
    [root@test ~]# [ ! "$USER" = "opesn" ]
    [root@test ~]# echo $?
    0
    [root@test ~]# 
    
    -z 值为0,则为真
    -n 值不为0,则为真
    [root@test ~]# [ -n "" ] && echo 0 || echo 1
    1
    [root@test ~]# [ -n "s" ] && echo 0 || echo 1
    0
    [root@test ~]# 
    [root@test ~]# [ -z "s" ] && echo 0 || echo 1
    1
    [root@test ~]# [ -z "" ] && echo 0 || echo 1
    0
    
    
    

    正则对比

    正则比对 [[]] 
    取反 ! 写在表达式的前面
    [root@test ~]# [[ $USER =~ ^r ]]
    [root@test ~]# echo $?
    0
    [root@test ~]# [[ $USER =~ ^n ]]
    [root@test ~]# echo $?
    1
    [root@test ~]# 
    [root@test ~]# [[ ! $USER =~ ^n ]]
    [root@test ~]# echo $?
    0
    [root@test ~]# [[ ! $USER =~ ^r ]]
    [root@test ~]# echo $?
    1
    [root@test ~]# 
    
    

    if判断

    #单分支(单分支:一个条件一个结果)
    [root@test test]# vim if.sh
    #!/bin/bash
    if [ -f /etc/passwd ];then
            echo "yes"
    fi
    
    #双分支(双分支:一个条件两个结果)
    [root@test test]# vim if.sh
    #!/bin/bash
    
    if [ -f /etc/passwdd ];then
            echo "passwdd file is yes"
    else
            echo "passwdd file is no"
    fi
    
    #多分支(多分支:多个条件多个结果)
    [root@test test]# vim if.sh
    #!/bin/bash
    
    if [ -f /etc/passwdd ];then
            echo "passwdd file is yes"
    elif [ -f /etc/passwddd ];then
            echo "passwddd file is yes"
    elif [ -f /etc/passwd ];then
            echo "passwd file is yes"
    fi
    

    case语句

    case 变量 in
    	变量内容1)
    			命令组
    			;;
    	变量内容2)
    			命令组
    			;;
    	变量内容3)
    			命令组
    			;;
    	*)
    			echo "请输入正确的变量"
    esac
    
    

    case语句书写

    [root@test ~]# vim jumpserver.sh 
    #!/bin/bash
    clear
    cat <<EOF
            * * * * * * * * * * * * * * *
            *       1.m01=10.0.1.61     *
            *       q.退出              *
            * * * * * * * * * * * * * * * 
    EOF
    trap "" INT HUP TSTP
    while true
    do
    read -p "请输入你要连接的服务器:" sum
    case $sum in
            1)
              clear
              ssh 10.0.1.61
              clear
              cat <<EOF
            * * * * * * * * * * * * * * *
            *       1.m01=10.0.1.61     *
            *       q.退出              *
            * * * * * * * * * * * * * * * 
    EOF
              ;;
            q)
              exit
              ;;
            *)
                       cat <<EOF
            * * * * * * * * * * * * * * *
            *       1.m01=10.0.1.61     *
            *       q.退出              *
            * * * * * * * * * * * * * * * 
    EOF
    esac
    done
    

    for循环

    for  变量名称 in  取值列表  (数字 字符串  `cat 文件` 命令)
    do
    		命令
    		echo hehe
    done
    

    for循环书写

    [root@test ~]# vim ping.sh 
    #!/bin/bash
    . /etc/init.d/functions
    for i in {60..65}
    do
            {
            ping -c1 -w1 10.0.1.$i &>/dev/null
            [ $? -eq 0 ] && action "ping 10.0.1.$i is ok" /bin/true
            } &
    done
    wait
    echo "在线取IP is ok"
    
    
    

    while循环

    while [ 条件 ] 为真则执行 为假退出

    [root@test ~]# vim while_sum+.sh 
    #!/bin/bash
    sum=0
    i=1
    while true
    do
            sum=$[${sum}+${i}]
            [ $i -eq 100 ] && echo $sum && exit
            ((i++))
    done
    
    
    

    语句控制

    exit     	#直接退出整个脚本
    break    	#跳出循环体 执行循环体外的命令
    continue 	#跳出当前的循环 继续下一次循环
    
    

    exit

    [root@test test]# cat exit.sh 
    #!/bin/sh
    while true
    do
    	echo hehe
    	exit
    done
    echo done.......
    [root@test test]# bash exit.sh 
    hehe
    [root@test test]# 
    
    

    break

    [root@test test]# cat break.sh 
    #!/bin/sh
    while true
    do
    	echo hehe
    	break
    done
    echo done.......
    [root@test test]# bash break.sh 
    hehe
    done.......
    [root@test test]# 
    

    continue

    [root@test test]# cat continue.sh
    #!/bin/sh
    for i in {1..5}
    do
    	[ $i -eq 4 ] && continue
    	echo $i
    done
    echo done.......
    [root@test test]# bash continue.sh
    1
    2
    3
    5
    done.......
    [root@test test]# 
    
    
    

    函数

    1) 完成特定功能的代码块
    2) 代码模块化 便于复用和可读
    3) 和变量类似 必须先定义在调用,如果不调用则函数不会执行
    
    

    函数的定义方法

    [root@test test]# cat function.sh
    #!/bin/sh
    fun1(){
    	echo "函数第一种定义方式"
    }
    function fun2 {
    	echo "函数第二种定义方式"
    }
    function fun3(){
    	echo "函数第三种定义方式"
    }
    fun1
    fun2
    fun3
    [root@test test]# bash function.sh
    函数第一种定义方式
    函数第二种定义方式
    函数第三种定义方式
    [root@test test]# 
    
    

    函数的传参

    [root@test test]# cat fun.sh 
    #!/bin/bash
    
    fun() {
    	echo 1
    	echo "$1"
    	return 100
    }
    
    fun $1
    [root@test test]# bash fun.sh 2
    1
    2
    [root@test test]# 
    
    

    函数的本地变量local

    [root@test test]# cat fun.sh
    #!/bin/sh
    fun1(){
    	 local num=20
    	 for i in `seq 30`
    	 do
    		 total=$[num+i]
    	 done
    	 echo "结果为:$total"
    }
    fun1
    echo $num
    [root@test test]# bash fun.sh 
    结果为:50
    
    [root@test test]# 
    
    

    return 返回值

    [root@test test]# cat fun.sh
    #!/bin/sh
    fun(){
    	if [ -f "$1" ];then
    	   return 50
    	else
    	   return 100
    	fi
    }
    fun $1
    re=$?
    [ $re -eq 50 ] && echo "$1 文件存在"
    [ $re -eq 100 ] && echo "$1 文件不存在"
    [root@test test]# bash fun.sh /etc/hosts
    /etc/hosts 文件存在
    [root@test test]# bash fun.sh /etc/hostsssssssss
    /etc/hostsssssssss 文件不存在
    [root@test test]# 
    

    数组

    普通数组

    只能使用数字作为索引
    1) 数组的定义格式
    第一种定义方式
    数组名[索引名]  默认的索引从0开始
    数组名[下标]=值
    第二种定义方式
    数组名=([0]=值 [1]=值 [20]=值)
    第三种定义方式
    array=(shell mysql kvm docker)
    array=(shell mysql kvm docker [10]=test [20]=hehe)
    2) 查看数组的值
    echo ${array[0]}
     3) 查看数组的索引
    [root@backup ~]# echo ${!array[*]}
    
    [root@test test]# cat array.sh
    #!/bin/bash
    IPS=(
    114.114.114.114
    223.5.5.5
    )
    for i in ${IPS[*]}
    do
    	ping -c 1 -W 1 $i &>/dev/null
    	[ $? -eq 0 ] && echo ok|| echo error
    done
    [root@test test]# bash array.sh
    ok
    ok
    [root@test test]# 
    
    

    关联数组

    declare -A array  声明关联数组
    [root@backup ~]# declare -A array
    [root@backup ~]# array[index1]=shell
    [root@backup ~]# array[index2]=MySQL
    [root@backup ~]# array[index3]=KVM
    [root@backup ~]# echo ${array[*]}
    shell MySQL KVM
    [root@backup ~]# echo ${!array[*]}
    index1 index2 index3
    
    [root@test test]# cat sex.txt 
    m
    m
    m
    f
    f
    f
    m
    f
    m
    x
    [root@test test]# cat array.sh
    #!/bin/sh
    declare -A array
    while read line
    do
    	let array[$line]++
    done<sex.txt
    for i in ${!array[*]}
    do
    	echo "$i 出现了 ${array[$i]} 次"
    
    done
    [root@test test]# bash array.sh
    f 出现了 4 次
    m 出现了 5 次
    x 出现了 1 次
    [root@test test]# 
    
  • 相关阅读:
    酒里放茶,醉,未遂。
    利用自定义事件实现不同窗体间的通讯 Delphi篇
    主题:CS0016: 未能写入输出文件“c:&#92;WINDOWS&#92;Microsoft.NET&#92;***.dll”错误处理
    delphi點擊窗體最小化,關閉按鈕時的托盤圖標設置
    delphi制作程序啟動歡迎窗體
    那年 那雪
    DOL魔盘解决方案
    专家解密“艳照门”背后三大安全陷阱
    jQuery获取Select选择的Text和 Value(转)
    技术列传 guava cache
  • 原文地址:https://www.cnblogs.com/opesn/p/11444606.html
Copyright © 2020-2023  润新知