• shell编程(二):变量、条件测试


    1.shell变量

    shell变量没有类型的概念,全是字符串

    1)自定义变量

    变量作用:用一个特定的字符串表示一不固定的内容

    定义变量:变量名=值  变量名必须以字母或下划线开头(显示赋值

    引用变量:$变量名或者 ${变量名}

    取消变量:uset 变量名

    ${#变量名}  显示变量值的长度;加{}可以防止歧义

    例子:

    #!/bin/bash
    
    ip=www.baidu.com
    
    if ping -c1 $ip &> /dev/null;then
    
            echo "$ip is ok"
    
    else
    
            echo "$ip is down"
    
    fi

    then是单独的命令,因此前面要加分号。fiif的倒置,表示结束

     或者:

    #!/bin/bash
    
    ip=www.baidu.com
    
    ping -c1 $ip &>/dev/null
    
    if [ $? -eq 0 ];then
    
            echo "$ip is ok"
    
    else
    
            echo "$ip is down"
    
    fi

    注:[]是用来做条件测试的。$?是上个命令的返回值。$? -eq 0表示上个命令的返回值是0.注意前面和后面有空格。因为[是命令,命令和选项参数之间有空格。[是命令,]是参数,和[搭配使用。

    隐式赋值read

    从键盘读入

    在脚本中写入 read 变量名

    然后在命令行执行时从键盘读入赋值。

    read -p “please input a ip:  ” 变量名   #给用户提示

    read可以同时定义多个变量   read name sex age  #在输入时以空格分隔

    $1 表示脚本后面的第一个参数。位置变量(在脚本后的位置)

    可以将一个变量的值赋给另一个变量 a=”$b is you”   #注意是弱引用(双引号)

    使用反引号进行命令替换  a=`cat a.txt`  执行一遍再赋值给a

    上面最后都是一个字符串

    2)环境变量

    环境变量和自定义变量作用范围不一样。自定义变量在当前shell有效,在子shell和其他都无效。环境变量在全局都有效

    定义环境变量:方法1export 变量名=

    方法2export 自定义变量名   将自定义变量转成环境变量

    引用环境变量: $变量名  或者${变量名}

    查看环境变量:echo $变量名    或者 env 查看所有

    例子:
    在某个脚本publish.sh有自定义变量ip1,在其他脚本如1.sh想要publish.sh里的自定义变量,只需要在1.sh中执行publish.sh就能在当前shell中引入,方法为. publish.sh。写项目时公共变量可以定义在公共的脚本中,不需要定义成环境变量。

    /etc/profile里有系统定义好的环境变量。echo $PATH

    如果想修改PATH,即新添shell的搜索路径,可以在profile文件后新加:
    PATH=$PATH:/new/bin

    export PATH    在当前shell和子shell就都可以用环境变量

    source /etc/profile 在当前shell执行之前修改的文件,导入环境变量(不写该命令就要新开shell才能实现加载)

    系统定义好的环境变量有:PATHUSERUIDMAILSHELLHOME等。可以在脚本直接拿来用。$环境变量

    3)位置变量

    $1$2....、根据执行脚本时所带的位置的参数来确定的变量。在脚本中可以直接用。

    4)预定义变量

    $?:上个命令的返回值,0表示成功

    $!:上一个后台进程的PID

    $$:当前进程的PID

    $#:参数的个数

    $@或者$*:所有的参数

    $0:脚本名

    $*$#的区别:

    $*$@没有被引用的时候,它们确实没有什么区别,都会把位置参数当成一个个体。

    "$*"会把所有位置参数当成一个整体(或者说当成一个单词),如果没有位置参数,则"$*"为空,如果有两个位置参数并且IFS为空格时,"$*"相当于"$1 $2"

    "$@" 会把所有位置参数当成一个单独的字段,如果没有位置参数($#0),则"$@"展开为空(不是空字符串,而是空列表),如果存在一个位置参数,则"$@"相当于"$1",如果有两个参数,则"$@"相当于"$1" 和"$2"等等

    引号

    ”$1”和’$1’的区别:”$1”会引用这个值,而’$1’会直接显示$1(echo ”$1” echo ’$1’)

    ‘’单引号中没有变量(强引用).双引号是弱引用。

    ``反引号,命令替换,里面内容先被shell执行,在替换进去。比如touch `date +%F`_file.txt

    $()与反引号相同

    例子:

    disk_free=$(df -h | grep ‘/$’ | awk ‘{print $4}’)  

    #df -h显示挂载信息  /$ /结尾的

    脚本例子

    basenamedirname$0是带路径的文件名。但前面加个basename就只有文件名。

    反引号的作用就是将反引号内的Linux命令先执行,然后将执行结果替换

    if [ ! -f $1] 条件测试中,判断$1是否是个文件。加个!表示不是文件会执行

    
    

     #!/bin/bash

    #如果用户没有加参数
    if [ $# -eq 0 ];then
        echo "usage:`basename $0` file"
        exit
    fi

      (5)变量的运算

    整数运算

     方式1let

    let sum = 1+2;echo $sum

     方式2$((表达式))

    num1=10
    
    num2=20
    
    echo $(($num1+$num2))

        + - * /   括号里的$可以省略

     方式3$[表达式]

     方式4expr

    num1=10
    num2=20
    expr $num1 + $num2

       #30  。直接echo就是10+20

    但要把结果赋给某个变量就要加反引号

    sum=`expr $num1 + $num2`    *要转义下  *     + - * /

      

    例子1:内存的使用率  

    mem_used=$(free -m | grep ‘^Mem’ | awk ‘{print $3}’)    #awk后面必须是单引号
    
    mem_total=$(free -m | grep ‘^Mem’ | awk ‘{print $2}’)
    
    mem_percent=$((mem_used*100/mem_total))
    
    echo “当前内存使用的百分比:$mem_percent” 

    bash -vx 脚本名  用调试的方式去执行

     

    例子2

    #!/bin/bash
    ip=www.baidu.com
    i=1
    while [ $i -le 5 ]
    do
            ping -c1 $ip &> /dev/null
            if [ $? -eq 0 ];then
                    echo "$ip is up"
            fi
            let i++
    done

    方法5bc

    bc是个交互式的计算器

    echo “2*4”|bc  将字符串创给bc

     

     小数运算:

    echo  “scale=2;6/4”|bc
    awk  ‘BEGIN{print 1/2}’
    echo5.0/2’|python

     6)变量“内容”的删除和替换

    内容删除  #注意:删除并没有改变变量,只是这一次输出改变了

    url=www.sina.com.cn

    #是从前往后删

    echo ${url}

    echo ${#url}

    echo ${url#www.}     #删除了www.

    echo ${url#*si}       #删除了si之前(包括si)的内容

    echo ${url#*.}       #删除了第一个.前(包括.)的所有内容   #最短匹配

    echo ${url##*.}      #删掉最后一个.之前的所有内容      #贪婪匹配

     

    %是从后往前删

    echo ${url%.cn}

    echo ${url%.*}    #从后往前删,删到第一个点

    echo ${url%%.*}    #从后往前删,删到最后一个点

     

    索引和切片

    echo ${url:0:5}    0~5的位置

    echo ${url:5}    从第5个位置,要后面全部

     

    内容替换

    echo ${url/sina/baidu}   #sina换成baidu   非贪婪匹配,只换1

    echo ${url//n/N}       #将所有的n换成N。不加双斜线就换第1个。 贪婪匹配

     

    变量的替代

    ${变量名-新的变量的值}

    如果变量没有被赋值,会用新的变量值替代。(没有被赋值是指被unset了的变量)

    变量有被赋值(包括空值:被定义过但是空值),不会被替代

    echo ${var1-aaa}

     

    ${变量名:- 新的变量的值}

    没有值或者空值会被替代;有值不会被替代

     

    7)变量i++++i

    对变量值i的影响:没有任何区别

    i=1; let i++ ; echo $i  #结果是2

    j=1;let ++j ; echo $j   #结果是2

    对表达式值的影响: 不同

    i=1; let x=i++ ; echo $x   #先赋值,再运算   1

    j=1 ; let y = ++i ; echo $y   #先运算,再赋值  2

    上面ij的值还都是2

    user[i++]   user[0]  user[1] ....

    user[++i]   user[1]  user[2] ....

    不去定义变量初始值,一般都是0

    let i++ ; echo $i  1

    if [ ! -f $1 ];then
            echo "error file"
            exit
    fi
     
    echo 'ping......'
    for ip in `cat $1`   #执行单引号里的命令,即显示ip,并且遍历
    do
            ping -c1 $ip &> /dev/null
            if [ $? -eq 0 ];then
                    echo "$ip is up"
            else
                    echo "$ip is down"
            fi
    done

      

    2.条件测试

    1)概述

    条件测试分为三类:文件测试(测试文件是常规文件还是设备文件、是不是有写、执行权限等、判断文件是否存在);数值比较字符串比较

    test -d /home 判断/home是否是目录。不会显示任何结果,但是的话返回值为0

    例子:

    #!/bin/bash
    
    back_dir=/var/mysql_back
    
    if ! test -d $back_dir;then        #如果不是目录,就创建
    
    # if [ ! -d $back_dir ];then   
    
            mkdir -p $back_dir
    
    fi
    
    echo "开始备份..."

     [ test命令一样

    [ -d /home ]    #  [是命令,-d是选项,/home]是参数,之间必须有空格。

     

    例子2:数值比较;root用户才能安装httpd

    if [ ! $UID -eq 0 ];then
    
    # if [ $UID -ne 0 ];then
    
    #if [ $USER ! = “root” ];then   #字符串比较
    
    echo “你没有权限”
    
    exit
    
    fi
    
    yum -y install httpd

     测试格式有三种:

    test 表达式

    [ 条件表达式 ]

    [[ 条件表达式 ]]    #可以用正则~

     

    man test看帮助文档

     

    2)操作

    文件测试

    语法: [ 操作符 文件或目录 ]

    [ -e dir/file ]    #判断目录或者文件是否存在,存在就为真

    [ -d dir ]    #是否存在,并且是目录

    [ -f file ] #是否存在,并且是文件

    [ -r file ] #当前用户对该文件是否有读权限

    [ -x file ] #执行

    [ -w file ] #

    [ -L file ]     #是否是链接

    [ -b file ]     #是否是设备文件

     

    数值比较

    [ 1 -gt 10 ] #大于

    [ 1 -lt 10 ] #小于

    -eq 等于

    -ne 不等于

    -ge  大于等于

    -le  小于等于

     

    输入用户名,判断用户是否存在,创建用户。

    #!/bin/bash
    
    read -p "please input a user name: " user_name
    id $user_name &>/dev/null  #查看用户id,用户存在会执行成功
    if [ $? -eq 0 ];then
    #if id $user_name &>/dev/null;then
            echo "用户存在"
            exit
    fi
    useradd $user_name
    if [ $? -eq 0 ];then
            echo "用户创建成功"
    fi

    例子:磁盘根分区的使用量>90%就报警

    df -TH   查看磁盘的使用量

    df -TH | grep ‘/$’ | awk ‘{print $(NF-1)}’      #NF是倒数第一列,NF-1是倒数第二列   #9%
    df -TH | grep ‘/$’ | awk ‘{print $(NF-1)}’ | awk -F”%” ‘{print $1}’   #-F”%” %分割,取前面数字    # 9

    disk_use = $(df -TH | grep ‘/$’ | awk ‘{print $(NF-1)}’ | awk -F”%” ‘{print $1}’)   #将执行结果赋给变量。由于是命令,需要变量替换 $()或者反引号。

    if [ $disk_use -ge 90 ];then

    echo “`date  +F%-%H` disk : ${disk_use}%” | mail -s “disk war....”  $mail_user

    fi

     

    计划任务crontab  -e  打开一配置文件,里面写任务。

    格式:

    */5 * * * *     /bin/bash  /root/scripts/disk_use.sh    

    */5 * * * * 代表每隔5分钟

    /bin/bash 代表解释器

    /root/scripts/disk_use.sh   为执行的脚本

      

    可以定时执行脚本,输出内容到指定日志中。

     

    字符串比较:

    提示:使用双引号(防止变量没有报错;也可以不使用双引号,但不好)

    [ “$USER” == “root” ]     判断当前用户是不是root用户   ==或者=都行

    !=

    [ -z “$BBB” ]    判断BBB变量的值的长度是0

    [ -n “$BBB” ]    判断BBB变量的值的长度不是0

    变量为空或者未定义,长度都是0.

      

    逻辑运算

    [ 表达式1 -a 表达式2 ]    两个都成立      

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

    [[ 表达式1 && 表达式2 ]]   双括号的并

    [[ 表达式1 || 表达式2 ]]     或者

     

    例子:

    批量生成用户

    seq 10  生成1-10的序列 seq 3 2 10 生成3-10的数,步长为2

    #!/bin/bash
    
    #useradd
    
    #v1.0 by yq 12/2/2020
    
    read -p "please input number: " num
    
    #if [ “$num” = ^[0-9]+$ ];then     #这个是错误的,会直接比较后面的字符,单个方括号没有正则
    
    if [[ ! ”$num”=~^[0-9]+$ ]];then   # ~代表匹配的意思.后面不能加双引号。
    
    echo “请输入数字”
    
    exit
    
    fi
    
    read -p "please input prefix: " prefix
    
    if [ -z “$prefix” ];then
    
    echo “长度不能为0”
    
    exit
    
    fi
    
    for i in `seq $num`      #{1..$num}不行,借助seq命令生成序列
    
    do
    
            user=$prefix$i
    
            useradd $user
    
            echo "123" |passwd --stdin $user &>/dev/null
    
            if [ $? -eq 0];then
    
                    echo "$user is created"
    
            fi
    
    done

       

    while循环直到输入数字

    read -p “请输入数字” num
    
    while true
    
    do
    
    if [[ “$num”=~^[0-9]+$ ]];then
    
      break
    
      else
    
        read -p “不是数字,请输入数字” num
    
    fi
    
    done

      符号小结:

    ()  在子shell中执行

    (( )) c风格的数值比较   ((1<2))

    $()   命令替换,与反引号相同。先执行命令,再替换

    $(()) 整数运算 $((1+2))

     

    {} 集合{1..3}

    ${} 变量的引用

     

    [] 条件测试

    [[]] 条件测试,多了按正则比较的方式(=~

    $[] 整数运算

     

    执行脚本:
    ./01.sh 需要执行权限 在子shell中执行

    bash 01.sh 不需要执行权限  在子shell执行

    . 01.sh 不需要执行权限,在当前shell执行

    source 01.sh 不需要执行权限,在当前shell执行

     

    调试脚本:

    sh -n 02.sh 仅调试语法错误

    sh -vx 02.sh 以调试的方式执行,查询整个执行过程

     

  • 相关阅读:
    cpu时钟周期
    调参学习
    力扣:堆
    学习率衰减问题
    力扣:图之并查集问题
    Java判断空字符串
    python读取文件通过正则过滤需要信息然后保存到新文件里
    python换行写入文件
    Robotium solo.goBack();不起作用,解决方案
    Android清除本地数据缓存代码
  • 原文地址:https://www.cnblogs.com/yq055783/p/13091089.html
Copyright © 2020-2023  润新知