存档十二月 2020

shell_脚本练习.sh




shell 练习脚本


脚本00 变量例子
    ping.sh
        #!/bin/bash
        #变量的使用 脚本

        if [ $# -eq 0 ]; then
                echo "paease add ip file"
                echo "usage: `basename $0` file"
                exit
        fi

        if [ ! -f $1 ]; then
                echo "error file"
                exit
        fi

        for ip in `cat $1`
        do
                ping -c1 $ip &>/dev/null
                if [ $? -eq 0 ]; then
                        echo "$ip is up."
                else
                        echo "$ip is down."
                fi
        done


脚本01 删除用户            \\ 使用 if case 判断
    #!/bin/bash
    read -p "please input want delete a user " user
    if [ -z $user ]; then
            echo "can't empty;"
            exit 1
    fi
    id $user >/dev/null 2>&1
    if [ $? -eq 0 ]; then
            :
    else
            echo "no such user $user"       
            exit 2
    fi
    read -p "Are you sure delete $user (Y/N)" i
    case "$i" in
    y|Y|yes|YES)
            userdel -r $user
            echo "delete $user"
            ;;
    *)
            echo "input error can't $user"
            ;;
    esac

    #if [ $i = "y" -o $i = "Y"  ]; then
    #       userdel -r $user
    #       echo "delete $user"
    #else
    #       echo "input error can't $user"
    #       exit 3
    #fi


脚本02 简单的 jump_server
    #!/bin/bash
    #cat <<-EOF >>/home/teo/.bash_profile       \\ 用户级别的 登录执行的文件
    #/home/teo/jump_server.sh
    #EOF
    trap "" HUP INT OUIT TSTP                     \\ trap 信号捕捉  遇到这些信号 不做任何操作 不能退出
    web1=192.168.10.12
    web2=192.168.10.13
    mysql=192.168.10.14
    clear
    while :
    do
    cat <<-EOF                                           \\ 打印菜单
    1. web1
    2. web2
    3. mysql
    EOF
    echo -en "\e[1;35mplease input number: \e[0m"
    read num
    case "$num" in
    1)
            ssh teo@$web1
            ;;
    2)
            ssh teo@$web2
            ;;
    3)
            ssh teo@$mysql
            ;;
    "")
            ;;
    *)
            echo "error"
            ;;
    esac
    done


脚本03 一直ping脚本
    #!/bin/bash
    #ip=192.168.10.$i
    #>a.txt                    # 重定向a.txt  清空a.txt

    while :
    do
            for i in `seq 1 254`
            do
                    {
                    ip=192.168.10.$i
                    ping -c5 $ip &>/dev/null
                    if [ $? -eq 0 ]; then
                            echo -e "\e[1;35m$ip is ok \e[0m" | tee -a a.txt         # tee -a 追加 到a.txt
                    else
                            echo -e "\e[1;31m$ip is donw \e[0m" | tee -a a.txt
                    fi
                    } &                   # 把上面 { } 中的代码后台执行 在子shell中执行
            done
            wait                          # 等待他前面所有的后台进程结束才执行下面的代码
    sleep 10
    done


脚本04 一直ping脚本
    #!/usr/bin/bash
    while :
    do
            for ip in `cat url.txt`
            do
                    {
                    ping -c5 $ip &>/dev/null
                    if [ $? -eq 0 ]; then
                            echo -e "\e[1;35m$ip is up \e[0m"
                    else
                            echo -e "\e[1;31m$ip is down \e[0m"
                    fi
                    } &
            done
            wait
            sleep 120
    done


脚本05 批量创建用户01
    #!/bin/bash
    while :
    do
            read -p "please enter name passwd num " name pass num
            printf "
            ------------------------
            you enter name is $name
            you enter pass is $pass
            you enter num  is $num 
            ------------------------
            "
            read -p "Are you sure[y/n] " action
            if [ "$action" = y ]; then
                    echo "create user now... "
                    break
            fi
    done

    for i in `seq $num`
    do
            id $name$i &>/dev/null
            if [ $? -eq 0 ]; then
                    echo "$user$i already exists"
                    continue                               # 跳出本次循环
            fi
            useradd $name$i
            echo "$pass" | passwd --stdin $name$i >>/dev/null
            echo "$name$i already create"
    done


脚本06 批量创建用户02
    #!/bin/bash
    # ./a.sh url.txt
    # 批量创建用户02 读取url.txt 一行的两个字段 第一字段赋予用户名 第二字段赋予密码
    # user1 123456
    # user2 123456  ... ... url.txt
    #IFS=$'\n'            # 定义for使用回车分隔符 默认空格  两种方式
    IFS='
    '
    for line in `cat $1`
    do
            name=`echo "$line" | awk '{print $1}'`
            pass=`echo "$line" | awk '{print $2}'`
            id $name &>/dev/null
            if [ $? -eq 0 ]; then
                    echo "the $name is already exists."
                    continue
            fi
            useradd $name &>/dev/null
            echo "$pass" | passwd --stdin "$name" &>/dev/null
            if [ $? -eq 0 ]; then
                    echo "the $name is create."
            fi
    done


脚本07 ping检测网段的主机是否存在
    #!/bin/bash
    #使用for
    for i in {1..254}
    do
            {
            ping -c1 -w1 172.21.34.$i &>/dev/null
            if [ $? -eq 0 ]; then
                    echo "$i is up.."
            fi
            } &
    done
    wait
    echo "ping finish all"

    #!/bin/bash
    #使用while
    i=1
    while [ $i -le 254 ]
    do
            {
            ip=172.21.34.$i
            ping -c1 -w1 $ip &>/dev/null
            if [ $? -eq 0 ]; then
                    echo "$ip is up.."
            fi
            }&
            let i++
    done
    wait
    echo "ping finish all...."

    #!/bin/bash
    使用until
    i=1
    until [ $i -gt 254 ]
    do
            {
            ip=172.21.34.$i
            ping -c1 -w1 $ip &>/dev/null
            if [ $? -eq 0 ]; then
                    echo "$ip is up...."
            fi
            }&
            let i++
    done
    wait
    echo "ping finish all .... "


脚本08 1--100相加
    #!/bin/bash
    #使用until循环
    i=1
    until [ $i -gt 100 ]
    do
            let sum+=$i
            let i++
    done
    echo "sum is $sum"
    
    #!/bin/bash
    #使用while循环
    i=1
    while [ $i -le 100 ]
    do
            let sum+=$i
            let i++
    done
    echo "sum is $sum"


    #/bin/bash
    #使用for循环
    for i in {1..100}
    do
    #       let sum=$sum+$i
            let sum+=$i
    done
    echo "sum is $sum"


脚本09 多线程 控制进程的数量
    #!/bin/bash
    # 此脚本为控制多线程的数目 太多会影响机器的性能 命名管道可以多个shell共同使用
    # 利用管理文件的特性 读取一行 会少一行 内容不会覆盖 会追加 来控制 多线程的数目
    thread=5                      #定义多线程 数目为5
    tmp_fifofile=/data/$$.fifo    #定义 自定义命名管道的位置 .fifo管道文件后缀 $$当前进程的pid 仅仅用于名字 其他也可 为了不重复
    mkfifo $tmp_fifofile          #创建 命名管道
    exec 8<> $tmp_fifofile        #打开此管道 使用8描述符打开
    rm -f /data/$$.fifo           #可以不删除 但是会存留  删除了也不影响 已经使用描述符打开
    for i in `seq $thread`        #往管道描述符里面的扔5行文件 这里扔了五个回车 亦可以扔其他的
    do
            echo >&8              #echo 后面什么都没有会 输出一个回车符 >重定向符号 但是管道文件特殊 不会覆盖 会追加
    done                          #&8 为调用 为8的描述符 即 往描述符8的文件 写入回车

    for i in {1..254}
    do
            read -u 8             # -u 从描述符里面读行  这里是从8里面读 读到就继续 读不到就等着读 以此控制多线程数目
            {
            ip=172.21.34.$i
            ping -c1 -w1 $ip &>/dev/null
            if [ $? -eq 0 ]; then
                    echo "$i is up.."
            else
                    echo "$i is down.."
            fi
            echo >&8              # 上面读取一个会少一个  在这里 补充一个
            }&
    done
    wait
    exec 8>&-                     # 释放文件描述符8  循环结束后释放
    echo "ping finish all... ..."


脚本10 expect 解决交互
    #!/usr/bin/expect
    #spawn 开启一个会话 注意解释器 /usr/bin/expect
    #expect 会出现的交互
    #出现yes/no 发送 yes \r回车 ;有可能不出现 跳过
    #出现密码 ;结束标识
    #interact交互 停在对方那边 不退出来 默认是退出
    spawn ssh root@192.168.10.13
    expect {
            "yes/no" { send "yes\r"; exp_continue }
            "password:" { send "123456\r" };
    }
    interact


脚本11 expect 变量的使用及发送命令  
    #!/usr/bin/expect
    #spawn 开启一个会话 注意解释器 /usr/bin/expect
    #expect 定义变量使用sed... [lindex $argv 0] 为位置变量 0表示第1个参数
    #使用 ./i.sh 192.168.10.13 root
    #send 可以发送一些在远程主机执行的命令
    set ip [lindex $argv 0]
    set user [lindex $argv 1]
    set password 123456
    set timeout 5
    spawn ssh $user@$ip
    expect {
            "yes/no" { send "yes\r"; exp_continue }
            "password:" { send "$password\r" };
    }
    #interact
    expect "#"
    send "ip a\r"
    send "pwd\r"
    send "exit\r"
    expect eof


脚本12 expect 主机 推送 公钥 密码一样的情况下
    #!/bin/bash
    #检测主机 如果主机存在则推送
    #expect eof 结束掉expect
    #set timeout 10  设置超时时间
    for i in {2..253}
    do
            {
            ip=192.168.10.$i
            ping -c1 -w1 $ip &>/dev/null
            if [ $? -eq 0 ]; then
                    echo "$ip" >> ip.txt
            /usr/bin/expect <<-EOF
            set timeout 10
            spawn ssh-copy-id $ip
            expect {
                    "yes/no" { send "yes\r"; exp_continue }
                    "password:" { send "123456\r" };
            }
            expect eof
            EOF
            else
                    echo "$ip" >> fale.txt
            fi
            }&
    done
    wait
    echo "all finish... ..."


脚本13 函数的简单使用
    #!/bin/bash
    # 函数计算与 传递参数
    # 1 只定义 调用 计算
    # 2 调用时候 赋值
    # 3 调用时候 传递参数
    mayann(){
    sum=0
    for((i=1;i<=5;i++))
    do
            sum=$[$sum+$i]
    done
    echo "mayann from 1 add 5 is sum $sum.."
    }
    mayann

    katana(){
    sum=0
    for ((n=1;n<=$m;n++))
    do
            sum=$(($sum+$n))
    done
    echo "katana from 1 add $m is sum $sum.."
    }
    m=8
    katana

    janice(){
    sum=0
    for ((i=1;i<=$1;i++))
    do
            let sum=$sum+$i
    done
    echo "janice from 1 add $1 is sum $sum.."
    }

    sssnow(){
    echo "$(($1*$2*$3))"
    }
    result=`sssnow $1 $2 $3`

    janice 10
    janice 20
    janice $1
    janice $2
    janice $3
    echo $result


脚本13 乘法表
    #!/bin/bash
    i=1
    for i in {1..9}
    do
            for ((j=1;j<=i;j++))
            do
                    echo -n "$j*$i=$[$i*$j] "
            done
            echo

    done


脚本14 for取所有的参数 计算
    #!/bin/bash
    # $@或$* 取所有的参数 赋给i
    # for i 后面的也可以省略 意思是 所有的参数 赋给i
    # shift 把参数 向左边 移动一位 删除一位  同 shift 1
    # 1 2 运算
    # 3 创建用户
    for i in $@
    do
            let sum+=$i
    done
    echo "use for sum is  $sum ..."

    while [ $# -ne 0 ]
    do
            let sum+=$1
            shift
    done
    echo "use while sum is  $sum ..."

    while [ $# -ne 0 ]
    do
            useradd $1
            echo "$1 user is create"
            shift
    done


脚本15 打印菜单 select 用法
    #!/bin/bash
    #PS3为系统变量 默认select 调用此变量 如果要修改显示则可以修改
    #PS1 可以 echo $PS1查看
    PS3="--choice--"
    while :
    do
    select i in disk memony cpu quit
    do
            case "$i" in
            disk)
                    df -h
                    break
                    ;;
            memony)
                    free -m
                    break
                    ;;
            cpu)
                    uptime
                    break
                    ;;
            quit)
                    break 2
                    ;;
            *)
                    echo "input error "     
                    break
            esac
    done
    done




    

shell 脚本




shell 脚本基础


1. 基础

    基础符号
        # echo $?   // 上一次命令成功 会返回0 不成功返回非0

        #!/bin/bash
            ping -c1 www.baidu.com &>/dev/null && echo "baidu is up"  || echo "baidu is down"

        #!       shebang  解释器   没有明确指定解释器shebang会生效  写shell脚本 可以不写 此行 不是注释
        &>       标准输出和错误输出 ping的结果 重定向到 黑洞/dev/null
        &> a.txt 意思是把 标准输出 和 标准错误输出 都重定向到文件file中

        2>&1    意思是把 标准错误输出 重定向到 标准输出  写成2&>1是不可以的
        >       默认为标准输出重定向,与 1> 相同

                0表示标准输入
                1表示标准输出
                2表示标准错误输出
                符号>& 是一个整体 不可分开,分开后就不是上述含义了。
                &>和>& 语义上是没有任何区别的,但是第一中方式是最佳选择,一般使用第一种

        &&  前一个命令才会执行后面的命令
        ||  前面命令失败 执行
        ;   命令的排序 不管前面命令成功与否 都执行后面的命令
        !   !为历史命令记忆功能 
            # !815      执行第815条命令
            # !vim      执行最近一个以vim开头的命令
            # tail !$   $为上一条命令的最后一个参数
            # !!        执行上一个命令

    快捷键

        # ^a        Ctrl + a   光标移动到命令最前面
        # ^e        Ctrl + e   光标移动到命令最后面  
        # ^k        Ctrl + k   删除光标后面的内容
        # ^u        Ctrl + u   删除光标前面的内容

        # ^r        Ctrl + r 搜索历史命令
        # ^d        退出 同exit
        # ^y        Ctrl + y   粘贴 ^k ^u 删除的内容
        # ^l        Ctrl + l   清屏  同 clear
        # ^s        Ctrl + s   冻结
        # ^q        Ctrl + q   恢复冻结 


    通配符       \\ 在shell中     在正则表达式中不一样
        *  匹配多个字符
        ?  匹配任意一个字符
        [] 匹配括号中的任意一个字符
            [abc]
            [a-z]
            [0-9]
            [a-z0-9]
            [^0-9]         ^ 取反

            # ls l[io]ve
        () 在子shell中执行命令
            # (umask 077; touch aa.txt)    \\ 设置umask值 创建aa.txt并赋予权限 umask的值不会影响到当前shell
        {} 集合
            # mkdir -p {1,2,a}             \\ 创建目录 1 2 a
            # mkdir -p a{1,2}               \\ 创建目录 a1 a2
            # mkdir -p {1..3}{a..c}          \\ 创建目录 1a 1b 1c 2a 2b 2c 3a 3b 3c
            # cp a.txt{,.bak}                 \\ 复制a.txt 到 a.txt.bak
        \ 转义符


2. 变量类型

    变量名必须以字母或下划线开头 区分大小写
        # vim a.sh
            ip=192.168.10.11                           \\ 定义一个变量ip 只在当前shell中生效
            read ip                                     \\ 从标准输入 读取
            read -p "please input a ip: " ip             \\ -p 给出提示 语句

            if [ $? -eq 0 ]; then                          \\ if判断
                    echo "$ip is up"
            else
                    echo "$ip is down"
            fi

    位置变量
        系统定义的 变量1 为脚本的第一个参数  引用为 $1
        $1
        $2
        ...
        ${10}


    自定义变量
        # ip1=3.3.3.3              \\ 自定义变量 只在当前shell中有效 在脚本中定义的属于 自定义变量
        # source a.sh               \\ 可以加载a.sh中定义的变量 但是只在当前shell中生效
        # . a.sh                     \\ . 同 source

        echo ${NAME:-tom}       \\ 变量 NAME 有值 返回NAME的值 如果没有值 显示 tom
        echo ${NAME:+tom}        \\ 变量 NAME 有值 返回 tom 如果没有值 那就没有值 啥都不返回
        

    系统定义的环境变量
        $HOSTNAME    \\ 获取主机名
        $UID          \\ 获取当前用户的uid 为0 则是root用户 可以判断是不是root用户
        $USER          \\ 获取当前用户的 用户名
        $LOGNAME        \\ 获取当前用户的 用户名

    环境变量
        # export ip2=4.4.4.4     \\ 环境变量 仅仅对当前shell及子shell中有效 一般不使用环境变量
        # export ip1              \\ 把已存在的 自定义变量 转换成 环境变量  关闭当前shell则失效
        # unset ip2                \\ 删除已经定义的 环境变量ip1
        # env                       \\ 查看所有的环境变量

        # echo $PATH                \\ 可以看到 PATH 路径
        # vim /etc/profile           \\ 环境变量 声明的 文件 对 所有用户有效 永久有效
            PATH=$PATH:/new/bin       \\ 可以新加 地址
            export PATH
        # source /etc/profile           \\ 重新加载文件
        # echo $PATH

        # vim /etc/profile
            HISTSIZE=5000               \\ 修改history 数目为5000
        # source /etc/profile            \\ 重新加载文件

    引用变量 2种方法
        $ip        \\ 引用变量ip
        ${ip}       \\ 引用变量ip 有分歧的地方 使用{}

    预定义变量         \\ 可用于脚本中的 参数 统计
        $0  脚本名       返回带路径的脚本名
        $*  所有的参数
        $@  所有的参数
        $#  参数的个数
            ${#i}            \\ 可以返回 变量 i 的长度
        $$  当前进程的PID
        $!  上一个后台进程的PID
        $?  上一个命令的返回值 0表示成功 

    # basename /data/a.txt        \\ 取文件的 文件名
        a.txt
    # dirname /data/a.txt           \\ 取文件的  目录名
        

    变量的赋值
        1 显示赋值
            ip=192.168.10.10
            school="bei jing"                \\ 引号里面可以有空格等
            today1=`date +%F`                 \\ 反引号里面 可执行语句 先执行 等于 $() 命令替换
            today2=$(date +%F)                 \\ (先执行)
        2 从键盘读取
            read ip                          \\ 从键盘输入读取
            read -p "input ip: " ip           \\ -p" " 为提示信息
            read -t 5 -p "input ip: " ip       \\ -t 5 设定时间 5秒
            read -n 2 name                      \\ -n 2 只取前两个字符
            read ip1 ip2                         \\ 可以定义多个变量 空格隔开

        " "    双引号 弱引用    可以引用变量的值
        ' '    单引号 强引用

    变量的运算
        方法 1
            expr 1 + 2               \\ +加  -减  \*乘   /除  %取余数    
            expr `$i + $n`            \\ 两个变量相加
            sum=`expr $sum + $i`       \\ 运算并赋值

            # expr 1 + 2 \* 5

            注: 都有空格
                默认会把计算结果输出到 屏幕
        方法 2                          \\ +加  -减  *乘  /除  %取余数
            echo $((1+2))                \\ $(())    里面放运算 算式
            echo $(($num1+$num2))         \\ 两个变量相加
            echo $((num1+num2))            \\ 两个变量相加    可以省略里面的 $符号
            echo $((5-3*2)) 
            echo $(((5-3)*2))                \\ 里面() 为先算
            echo $((2**5))                    \\ 2的5次方
            sum=$((1+2)); echo $sum            \\ 计算的值 给变量sum

            注:  用于 要运算的结果
                借助echo输出而已 默认没有输出
        方法 3
            echo $[]                 \\ +加  -减  *乘  /除  %取余数   用法同 $(())
        方法 4
            let i=2+3
            let i++         先赋值在计算
            let ++i         先计算
            let i=i+1

            let sum=$sum+$i     用sum的值加上i的值赋给sum    
            let sum+=$i         用sum的值加上i的值赋给sum
            let sum-=$i         用sum的值减去i的值赋给sum
            let sum*=$i
            let sum\=$i

            注: let用于变量赋值 时候的 运算
                不能加空格

    小数运算
        bc                       \\ 交互式计算器
        echo "2*4" | bc           \\ 一般使用传递参数 使用
        echo "2^4" | bc            \\ 2的四次方
        echo "scale=2;6/4"          \\ 保留两位小数

    变量的删除
        url=www.baidu.com      \\ 做以下操作不会对变量进行改变
        ${#url}                 \\ 获取变量的长度 可使用 echo ${#url} 协助查看
        ${url#www.}              \\ 删除 www.
        ${url#*bai}               \\ 删除 www.bai    *为匹配前面的字符
        ${url#*.}                  \\ 最短匹配 1个# 从前往后删除 到 第一个点 .
        ${url##*.}                  \\ 贪婪匹配 2个## 从前往后删除 到 最后一个点 .
        ${url%.com}                  \\ %从后往前删除
        ${url%.*}                     \\ 从后往前删除 到.
        ${url%%.*}                     \\ 从后往前删除 删除到最后一个点 .

        索引及切片
            url=www.baidu.com
                0123456789             \\ 对应的索引  一次类推10 11 12 ... ...
            ${url:0:5}                  \\ 从第0个索引取5个值
                www.b
            ${url:5:5}                    \\ 从第5个索引取5个值
                idu.c
            ${url:5}                        \\ 从第5个索引到最后

        替换
            url=www.baidu.com
            ${url/baidu/google}      \\ baidu 换个 googel

        替代
            ${var1-baidu.com}     \\ 变量var1  -为替代符号 如果变量var1有值或空值 则不替代 如果没有定义则赋予baidu.com
            ${var2:-baidu.com}     \\ 变量var2  :-为替代符号 如果变量var2有值则不替代 如果没有定义或空值则赋予baidu.com
            +
            :
            =
            :=
            ?
            :?

    脚本中的符号

        continue  \\ 跳过 跳过此次循环 执行下一次循环               只在循环中有效的参数
        break      \\ 跳出循环 结束循环  离开循环  执行后面的代码    只在循环中有效的参数
        break 1     \\ 同上 跳出 1层循环
        break 2      \\ 跳出 2层循环
        exit          \\ 结束符号  退出脚本 后面的代码 不在执行      任何时候碰到都退出脚本
        exit 1         \\ 返回1  可以任何一个数      默认返回0为成功
        shift           \\ 把参数 向左边 移动一位 删除一位  同 shift 1
        sleep 1          \\ 延迟1秒

        ()         子shell
        (())       运算 数值比较
        $()        命令替换    同 ` `   
        $(())      运算

        {}         集合
        ${}        变量引用 替换 替代

        []         条件测试  不支持正则
        [[]]       条件测试  支持正则表达式  
        $[]        整数运算

        # sh -vx a.sh     以调试的方式执行 查询整个执行过程
        # bash -vx a.sh   以调试的方式执行 查询整个执行过程
        # sh -n a.sh      检测语法
        # bash -n a.sh    检测语法

    执行方式:
        1 bash aa.sh    \\ 在子shell中执行 另开一个shell执行
          ./aa.sh

        2 . aa.sh          \\ 在当前shell中执行  希望脚本中的东西影响到当前 要在当前shell中执行
          source aa.sh


3. 条件测试

    1 test 条件表达式
        if test -d /data/www/; then         \\ -d 检测是否为目录
        else
        fi

    2 [ 条件表达式 ]                           \\ [ 为 关键字 同test        ]括号只为配合左边的
        if [ -d /data/www/ ]; then
        else
        fi

    3 [[ 条件表达式 ]]


    文件测试 符号
        -e dir|file   是否存在文件或目录
        -d dir        是否存在目录
        -f file       是否存在文件
        -r file       当前用户对改文件是否有读权限
        -x file       当前用户对改文件是否有执行权限
        -W file       当前用户对改文件是否有写权限      
        -L file       是否为链接文件
        -b            如果 FILE 存在且是一个块特殊文件则为真。  
        -c            如果 FILE 存在且是一个字特殊文件则为真。  

        -z            字符串的长度为零则为真。 字符串为空即NULL时为真。 
        -n            字符串的长度不为零则为真

        # if echo $a | grep -q '[^0-9]' &> /dev/null ;then     \\ 检测是否为数字

        以 [  为例子 同 test 和 [[

            # [ -L /etc/hosts ]; echo $?      \\ 是链接文件 返回0 不是非0
            # [ ! -d /data ]; && mkdir /data   \\ 不是目录返回真 则创建 
            # [ -d /data ]; || mkdir /data      \\ 是目录 返回真 则不执行后面的 不是目录返回假则创建   

    数值比较
        -eq   等于       equal 相等
        -ne   不等于      not equal 不等
        -gt   大于        greater than 大于
        -ge   大于等于    greater than or equal 大于或等于
        -lt   小于        less than 小于
        -le   小于等于    less than or equal 小于或等于

        ((1<2))        小于
        ((1==2))       等于
        ((1>2))        大于
        ((1>=2))       大于等于
        ((1<=2))       小于等于
        ((1!=2))       不等于
        ((`id -u`>0))  一个命令的结果 是否大于0
        (($UID==0))    一个命令的结果 是否等于0   

    字符串比较       \\ 一般都使用 " " 

        [ "$USER" = "root" ]
        [ "$USER" == "root"]
        [ "$USER" != "root"]
        [ -z "$BBB"]              字符长度是为0
        [ -n "$BBB"]              字符长度不为0

        [ 1 -lt 2 -a 5 -gt 10 ]         -a 并且  在 [ ] 里面加
        [ 1 -lt 2 -o 5 -gt 10 ]         -o 或者  在 [ ] 里面加
        [[ 1 -lt 2 && 5 -gt 10 ]]       && 并且  在 [[ ]] 里面加  支持正则表达式
        [[ 1 -lt 2 || 5 -gt 10 ]]       || 或者  在 [[ ]] 里面加


4. 循环 判断 语句

    case语句
        case "$aa" in
        111)
            命令
            ;;
        222)
            命令
            ;;
        333)
            命令
            ;;
        "")
            ;;                        \\ 输入为空 执行命令为空
        *)
            无匹配后 执行的命令            \\ 最后一个 可以不加 ;;
        esac

    :和 true 一样 都是永远返回为真  可用 用在死循环的条件上 或 if判断之后 执行一个为真的命令上


    if 语句


        if [ 条件 ]; then
        elif [ 条件 ]; then
        else
        fi

        if test ; then             \\ test 后跟 测试语句 相当于[ ]
        else
        fi

        if [[ 条件 ]]; then           \\ 支持正则表达式
        else
        fi

        if 条件; then
        else
        fi

        if ((条件)); then             \\ 数值比较
        else
        fi


    for 循环
        shell 风格
            for i in `seq 1 20`
            do
            done

            for i               \\ 没有 in 意思是取 所有的参数
            for i in {1..20}
            for i in 1 2 3 4 5
            for i in `cat ip.txt`     \\ 把文件url.txt 赋给 i
            for i in `cat $1`          \\ 把第1个参数文件 作为变量 赋给 i 
            for i in `seq 2 254`
            for i in `seq $n`

        c风格

            for((i=1;i<=5;i++))
            for((i=1;i<=$n;i++))

        IFS=$'\n'            \\ 定义for使用回车分隔符 默认空格  两种方式
        IFS='
        '                      \\ 第二种方法

        `seq 2 254`   产生序列

        seq 10     打印 序列 1-10
        seq 2 10   打印 序列 从 2 - 10
        seq 1 2 10 打印 序列 步长为2   1 3 5 7 9

        seq -w 10     -w 等位补齐
            01
            02
            ... ...
            10

        seq $i    可以使用变量


        if id teooo &>/dev/null; then         \\ if条件 形式01
        id teooo &>/dev/null
        if test $? -eq 0; then                  \\ if条件 形式02
        if [ $? -eq 0 ]; then                    \\ if条件 形式03


    while 循环                        循环不固定 一般使用while
        while 条件              条件为真的时候 循环
        do
        done

        while read line
        do
        done < a.txt

        while :              :为真或 true
        do
        done



    unit 循环                可用于 检查 是否上线

        unit 条件             与while相反 条件为假的时候循环
        do
        done

        unit false
        do
        done

        unit [ 1 -eq 2 ]
        do
        done

        unit asdfasdf &>/dev/null        随便写一个不存在的命令即可
        do
        done


    select 循环                常用于 打印菜单
        select i in aa bb cc
        do
        done


    expect 解决交互   看实例
        # yum install expect



    函数定义
        mayann(){

        }

        function mayann{

        }

        mayann             调用
        mayann 10          调用的时候 传递参数 传给$1


5. 正则表达式 RE

    基本元字符
        ^       行首定位符               ^love
        $       行尾定位符               love$
        .       匹配单个字符              l..e
        *       匹配前面的字符0到多次     ab*love

        []      匹配指定范围内的一个字符    [lL]ove                    \\ 只匹配一个
        [-]     匹配指定范围内的一个字符    [a-z]ove  [a-z0-9]ove       \\ 只匹配一个
        [^]     非  不在指定组内的字符    [^a-z0-9] [^a-Z]             \\ a-Z 涵盖 大写和小写

        \       用来转移元字符         love\.
        \<      词首定位符               \<love                  \\ 在这里 不是 转义符 整体是一个元字符
        \>      词尾定位符               love\>

        \(..\)  标签 后向引用                 s#\(www.\)#\1baidu.com#g
        \1  \2  调用 后项引用

        x\{m\}  字符x重复出现m次           o\{5\}
        x\{m,\} 字符x重复出现m次以上     o\{5,\}
        x\{m,n\}字符x重复出现m到n次     o\{5,10\}

        基本衍生常用组合

            .*          匹配多个字符
            ^$          空行          只有一个 回车 为空行
            ^[ \t]*$    空格或tab制表符有0个或多个 的行
            ^#          注释行 以#号开始的行
            ^[ \t]*#    #前面有有0个或多个空格或者tab制表符的行 也是注释行


    扩展元字符

        +       匹配1个或多个前面的字符    [a-z]+ove
        ?       匹配0个或1个前面的字符    lo?ve
        |       或者 a|b 匹配a或者b       love|hate
        ()      字符组                 loveadble|re    love(able|rs)ov    (ov)+

        (..)\1  标签 后项引用             (love)able\1er  

        x{m}    字符x重复m次             o{5}     [a-z]{9} 连续出现相同的英文字母9个
        x{m,}   字符x重复至少m次           o{5,}
        x{m,n}  字符x重复m到n次           o{5,10}


    POSIX字符
        [:alnum:]   字母与数字字符                 [[:alnum:]]  使用的时候在加 [] 为 匹配指定范围内的一个字符
        [:alpha:]   字母字符
        [:blank:]   空格与制表符
        [:digit:]   数字字母
        [:lower:]   小写字母
        [:upper:]   大写字母
        [:punct:]   标点符号
        [:space:]   换行符 回车 空格等在内的所有空白

    正则表达式 练习

        获取ip
            # ifconfig | grep 'inet' | sed -n '1p' |awk '{print $2}'

        内存剩余
            # free -m | grep Mem | awk '{print $4}'
        硬盘剩余
            # df -h | grep '/$' | awk '{print $4}'

        生成30位的随机口令
            # cat /dev/urandom | tr -dc "[:alnum:]" | head -c 1

        判断主机版本号
            # grep -o "[0-9]\+" /etc/centos-release | head -n1

        查出分区空间使用率的最大百分比值
            # df | grep '/dev/sd' | grep -o "[0-9]*%" | grep -o "[0-9]\+" | sort -n | tail -1
            # df | grep '/' | awk '{print $1,$5}' | sort -nr -k2 | head -n1

        删除 7天以前的备份文件
            find /data -mtime +7 | xargs rm -rf
            find /data -mtime +7 -exec rm -rf {} \;


6. shell 脚本加密
    gzexe 对 shell 脚本的加密与解密
        # gzexe a.sh             \\ 加密 a.sh 脚本 并同时生成源文件a.sh~ 
        # bash -x a.sh            \\ 调试 执行  以下为解密
            skip=44                \\ 第44 行的时候 进行了 压缩
        # tail -n +44 a.sh > a.gz   \\ 生成 a.gz 文件
        # gunzip a.gz
        # diff a.sh~ a                \\ a 为解密的文件
    shc 对 shell 脚本加密       \\ 亦可先使用shc加密 在使用 gzexe加密
        # yum install shc       \\ epel源
        # shc -v -r -f a.sh      \\ 加密 脚本   不对源文件进行操作
            a.sh.x.c              \\ 此为C语言的 源文件
            a.sh.x                 \\ 此为加密后的脚本 可以直接执行
        # mv a.sh.x b.sh
        # sh b.sh


7. shell 执行方式:
    1 bash aa.sh    \\ 在子shell中执行 另开一个shell执行
      ./aa.sh

    2 . aa.sh          \\ 在当前shell中执行  希望脚本中的东西影响到当前 要在当前shell中执行
      source aa.sh