0%

shell基础

文身(tattoo),又叫刺青,或指文身者,是用带有颜色的针刺入皮肤底层而在皮肤上制造一些图案或字眼出来,通过刺破皮肤而在创口敷用颜料使身上带有永久性花纹。

变量

一、分类

  1. 环境变量

    • 一般用大写字母表示,常见如:HOSTNAME、SHELL、HISTSIZE、USER、PATH、PWD、LANG、HOME、LOGNAME等。
    • 相关操作
      • 常看当前用户的环境变量:envexport
      • 查看某个具体的环境变量:echo $HISTSIZE
      • 设置某个环境变量如$PATH:PATH=/usr/local/someapp/bin:$PATH
      • 设置环境变量的几种方式
        • 直接修改/etc/profile,全部用户生效
        • 修改~/.bash_profile,当前用户生效
        • 使用export命令只对当前shell有效
  2. 普通变量,也称局部变量

    • shell是弱类型的语言,其变量通常不用指定类型或初始化,默认字符串类型。
    • 相关操作
      • 定义变量并赋值var=something
        • =左右不可有空格,否则就变成了比较运算符了
        • 变量值的引号(单双引号)可有可无,shell无要求
          • echo时双引号内部的变量可正常输出,单引号则不可
        • 加上export命令则升级为环境变量,如export var=something
        • 加上readonly命令则变为只读变量,如readonly var=something
          • 此时无法修改变量值,也无法unset变量,只有重新登录shell才能继续操作此变量(其实已经没啥关系了,关了此shell变量生命周期就结束了)。
      • 使用变量$var${var}
      • 销毁变量unset var
        • 不用加$符号
      • 查看变量setdeclare,输出结果包含普通变量和环境变量
      • 修改变量作用域
        • export命令可使变量在当前shell及子shell中都可访问,退出登录或脚本执行结束后失效
        • 将变量加入到/etc/profile,此时每个用户登录后都可访问此变量
          • source /etc/profile可使加入的变量立即生效
      • 取变量长度
        • 字符串类型${sharpvar},sharp代表#,md语法限制不能直接写
        • 数组类型${sharparr[@]}${sharparr[*]},sharp代表#,md语法限制不能直接写
    • 定义变量的三种形式
    1
    2
    3
    var1=abc
    var2='def'
    var3="ghi"
    • 使用变量echo $var1echo ${var2}
    • 删除变量unset var3
    • 将命令的结果赋值给变量
    1
    2
    var4=`ls`
    var4=$(ls)
  3. 特殊变量

    • $?:上一条代码执行的结果,0表示执行成功,否则为标准错误输出。

    • $$:当前shell的PID。

    • $!:最近一次执行的后台进程PID。

    • $#:统计参数的个数。

    • $@:所有参数。

    • $*:所有参数。

      • $@$*无双括号时等价,有双括号时差异明显

        • 编写echo.sh,代码见下方
        • 运行bash echo.sh
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        #!/bin/bash

        echo ===================================
        index=1
        echo "没有被双引号括起来的情况:\$*,所有的参数被认为是各个独立的单词"
        for arg in $*
        do
        echo "参数$index=$arg"
        let "index+=1"
        done

        echo ===================================
        index=1
        echo "被双引号括起来的情况:\$*,所有的参数被认为是一个单词"
        for arg in "$*"
        do
        echo "参数$index=$arg"
        let "index+=1"
        done

        echo ===================================
        index=1
        echo "被双引号括起来的情况:\$@,所有的参数被认为是各个独立的单词"
        for arg in "$@"
        do
        echo "参数$index=$arg"
        let "index+=1"
        done
    • $0:脚本名。

    • $n:参数位置。

  4. shell数组

    • 定义数组

      • 定义并初始化arr=(1 2 3)
      • 先定义再赋值
      1
      2
      3
      arr[0]=1
      arr[1]=2
      arr[2]=3
    • 取数组元素(数组元素的下标由0开始)

      • 取某个元素${arr[0]}
      • 取所有元素${arr[*]}或${arr[@]}
    • 取数组长度${ #arr[*]}${ #arr[@]}

二、进阶

  1. ${}的特殊用法

    • ${var:-word}:如果var为空或未定义则被赋值为word
      • ${var-word}:大体同上,除了var设置了但为空时变量的结果将是null,而不是word
    • ${var:+word}:如果var为空或未定义则不做任何操作,否则被赋值为word
    • ${var:=word}:如果var为空或未定义,则被赋值为word同时设置非空或已定义属性,否则为var自身
    • ${var:offset}:取子串,从offset处的后一个字符开始取到最后一个字符
    • ${var:offset:length}:取子串,从offset处的后一个字符开始取lenth长的子串
  2. 变量的切分、替换、提取

    • 变量提取

      • 使用通配符
      • 使用下标
    • 变量切分

    • 变量替换

  3. 在函数中可使用local命令定义局部变量,使其不影响函数外的同名变量

    • declare根据选项的不同,也可实现此功能
  4. 将算术表达式的结果赋值给一个变量要使用let命令

  5. 将标准输入的结果赋值给一个变量echo -n "Input:";read test


四大循环

循环(程序设计):是一种计算机科学运算领域的用语,也是一种常见的控制流程。

一、for

  1. 语法

    • C语言风格
    1
    2
    3
    4
    for((exp1; exp2; exp3))
    do
    statements
    done
    • Python语言风格,value_list的几种形式
      • 直接给出具体的值,如1 2 3 4
      • 给出一个取值范围{start..end},如{1..100}
      • 使用命令的执行结果(反引号或$()都可以取得命令的执行结果),如`seq 1 10`或$(seq 1 10)
        • 在markdown中使用双反引号可以让文章中的反引号正常显示
      • 使用shell通配符(可以认为是一种精简化的正则表达式)
      • 使用特殊变量,如$#$*$@$?$$等。
    1
    2
    3
    4
    for variable in value_list
    do
    statements
    done
  1. demo
1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
for ((i=1;i<=10;i++))
do
echo $i
done

#for i in 1 2 3 4 5 6 7 8 9 10
for i in `seq 1 10`
do
echo $i
done
  1. 方式一
1
2
3
4
5
#!/bin/bash
for ((i=1;i<=10;i++))
do
echo $i
done
  1. 方式二
1
2
3
4
5
#!/bin/bash
for i in {11..20}
do
echo $i
done
  1. 方式三
1
2
3
4
5
#!/bin/bash
for i in $(seq 21 30)
do
echo $i
done
  1. 方式四
1
2
#!/bin/bash
awk 'BEGIN{for(i=31;i<=40;i++) print(i)}'

二、seq命令(mac)

  1. seq [-w] [-f format] [-s string] [-t string] [first [incr]] last

    • -w, 填充0使得宽度相同
    • -f, 以指定格式
    • -s, 以指定字符串分割,默认(\n)
    • -t, 以指定字符串结尾
  2. demo

    • seq -w 0 0.1 1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    0.0
    0.1
    0.2
    0.3
    0.4
    0.5
    0.6
    0.7
    0.8
    0.9
    1.0
    • seq -f “%3g” 99 100
    1
    2
     99
    100
    • seq -s# 1 10
    1
    1#2#3#4#5#6#7#8#9#10#%
    • seq -t end 1 10
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    end

三、实战

文件内容log/1.txt

1
2
3
4
5
1
2
3
4
5

文件内容log/2.txt

1
2
3
4
5
6
7
8
9
10

循环读取单个文件内容

  • 方式一
1
2
3
4
5
#!/bin/bash
for i in `cat 1.txt`
do
echo $i
done
  • 方式二
1
2
3
4
5
#!/bin/bash
for i in $(cat 1.txt)
do
echo $i
done
  1. 读取文件夹下所有文件内容

    • 方式一
1
2
3
4
5
6
7
8
#!/bin/bash
for i in `ls /your_path`
do
for j in `cat /your_path/$i`
do
echo $j
done
done
  • 方式二
1
2
3
4
5
6
7
8
9
#!/bin/bash
path=/your_path/log
for i in `ls $path`
do
for j in `cat $path/$i`
do
echo $j
done
done

二、select

  1. 语法
1
2
3
4
select var in value_list
do
statements
done
  • 运行到select语句后,取值列表value_list中的内容会以菜单的形式显示出来,用户输入菜单编号就表示选中了某个值,这个值就会赋给变量 variable,然后再执行循环体中的statements
  • 其中value_list同for循环中Python风格中一致。
  • #?用来提示用户输入菜单编号。
  • ^D表示按下ctrl+d组合键,作用是结束`select循环。

select是无限循环(死循环),输入空值或者输入无效的值都不会结束循环,只有遇到break语句或按下ctrl+d组合键才能结束循环。

  1. demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
echo "What is your favourite OS?"
select name in "Linux" "Windows" "Mac OS" "UNIX" "Android"
do
case $name in
"Linux")
echo "Linux是一个类UNIX操作系统,它开源免费,运行在各种服务器设备和嵌入式设备。"
break
;;
"Windows")
echo "Windows是微软开发的个人电脑操作系统,它是闭源收费的。"
break
;;
"Mac OS")
echo "Mac OS是苹果公司基于UNIX开发的一款图形界面操作系统,只能运行与苹果提供的硬件之上。"
break
;;
"UNIX")
echo "UNIX是操作系统的开山鼻祖,现在已经逐渐退出历史舞台,只应用在特殊场合。"
break
;;
"Android")
echo "Android是由Google开发的手机操作系统,目前已经占据了70%的市场份额。"
break
;;
*)
echo "输入错误,请重新输入"
esac
done

三、while

  1. while循环用于不断执行一系列命令,也用于从输入文件中读取数据,命令通常为测试条件,其语法格式为:
1
2
3
4
5
while condition
do
commands
done

  1. demo

    • 正常循环判断
    1
    2
    3
    4
    5
    6
    7
    8
    #!/bin/bash

    num=0
    while [ $num -lt 5 ]
    do
    num=`expr $num + 1`
    echo $num
    done
    • 读取文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #!/bin/bash

    while read line
    do
    Bashuser=`echo $line | awk -F: '{print $1,$NF}' | grep 'bash' | awk '{print $1}'`
    if [ ! -z $Bashuser ]
    then
    echo "$Bashuser use bash shell."
    fi
    done < /etc/passwd

awk命令中,$NF代表的是最后一个字段,有关此命令的用法自行脑补

四、until

  1. 语法,意思是执行一系列命令commands直到条件conditiontrue时停止
1
2
3
4
until condition
do
commands
done
  1. demo
1
2
3
4
5
6
7
#!/bin/bash
num=1
until [ $num -gt 5 ]
do
echo $num
num=`expr $num + 1`
done

特殊变量和运算符

一、&

  1. &放在启动参数后面表示设置此进程为后台进程,进程切换到后台的时候把它称为job,切换到后台时会输出相关job信息

二、&&

  1. command1 && command2,表示&&左边的命令command1成功执行(即返回0)后,&&右边的命令command2才能够被执行。
    • command1执行不成功时,则command2也不会被执行,即发生了短路作用
  2. demo:cd ~/Desktop && touch 123.txt && mkdir test && cp 123.txt ./test/ && rm -f 123.txt

三、|

  1. 管道符号为一条竖线:”|”,是unix一个很强大的功能。

  2. 用法:command 1 | command 2,功能是把第一个命令command 1执行的结果作为command2的输入传给command 2

  3. demo:ls -s | sort -nr

    • -sfile size
    • -n是按数字排序numeric-sort
    • -r是反转reverse

该命令最终的效果是列出当前目录中的文件,并把结果作为sort命令参数,按数字递减顺序排序。

四、||

  1. command1 || command2,表示如果||左边的命令command1未执行成功,那么就执行||右边的命令command2
    • command1执行成功时,则command2不会被执行,同样发生了短路作用
  2. demo:cd ~/Desktop && rm -f 123.txt && cat 123.txt &>/dev/null || echo "cat failed"

五、()

  1. 把几个命令合在一起执行
  2. 一条命令需要独占一个物理行,如果需要将多条命令放在同一行则命令之间使用命令分隔符;分隔。
  3. 执行的效果等同于多个独立的命令单独执行的效果。
  4. ()表示在当前shell中将多个命令作为一个整体执行。
  5. 在执行前后都不会切换当前工作目录,也就是说命令组合都是在当前工作目录下被执行的(即便命令中有切换目录的命令)。
  6. demo:cd ~/Desktop && mkdir ./test && ls -al;(cd ~/Desktop/test;ls -al);ls -al
    • 可看到最终目录还是在~/Desktop

六、{}

  1. 把几个命令合在一起执行,作用同()
  2. demo:cd ~/Desktop && mkdir ./test && ls -al;{cd ~/Desktop/test;ls -al};ls -al
    • 可看到最终目录切换到了~/Desktop/test

七、特殊变量

  1. $$:Shell本身的PID(ProcessID)

  2. $!:Shell最后运行的后台Process的PID

  3. $?:显示最后命令的退出状态码,0表示没有错误,其他任何值表明有错误。

    • demo
    1
    2
    3
    4
    cd ~   
    echo $?
    cd ~/Desktop/not_exists_dir
    echo $?
  4. $-:显示Shell使用的当前选项,与set命令功能相同。

  5. $*:所有参数列表

  6. $@:所有参数列表

    • 没有被双引号括起来的时候$@$*一样的,见到IFS(默认为空格)就划分字段
    • 被双引号包起来的时候,$*将所有的参数认为是一个字段,$@以IFS来划分字段
  7. $#:添加到Shell的参数个数

  8. $0:Shell本身的文件名

  9. $1~$n:添加到Shell的各参数值,$1是第1参数、$2是第2参数…

  10. $^:所有的依赖文件,以空格分开(不包含重复的依赖文件)。

  11. $%:如果目标是归档成员,则该变量表示目标的归档成员名称。例如:如果目标名称为mytarget.so(image.o),则$@mytarget.so,而$%image.o

  12. demo

    • 脚本test.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#!/bin/bash
echo "脚本名称为:$0"
echo "参数个数为:$#"

echo ===================================

len=$#
for i in `seq 1 $len`
#for((i=1;i<=$len;i++))
do
echo "第"$i"个参数为:"${!i} # ${!i}表第i个参数,不能在花括号有美元符$
done

echo ===================================
echo "当前脚本进程ID为:$$"
echo "最后运行进程ID为:$!"

echo ===================================
echo "直接输出\$*: $*"
echo "直接输出\$@:$@"

echo ===================================
index=1
echo "被双引号括起来的情况:\$*,所有的参数被认为是一个单词"
for arg in "$*"
do
echo "参数$index=$arg"
let "index+=1"
done

echo ===================================
index=1
echo "被双引号括起来的情况:\$@,所有的参数被认为是各个独立的单词"
for arg in "$@"
do
echo "参数$index=$arg"
let "index+=1"
done

echo ===================================
index=1
echo "没有被双引号括起来的情况:\$*,所有的参数被认为是各个独立的单词"
for arg in $*
do
echo "参数$index=$arg"
let "index+=1"
done
  • 增加执行权限sudo chmod +x test.sh

  • 执行脚本./test.sh a b c d

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    脚本名称为:./test.sh
    参数个数为:4
    ===================================
    第1个参数为:a
    第2个参数为:b
    第3个参数为:c
    第4个参数为:d
    ===================================
    当前脚本进程ID为:13291
    最后运行进程ID为:
    ===================================
    直接输出$*: a b c d
    直接输出$@:a b c d
    ===================================
    被双引号括起来的情况:$*,所有的参数被认为是一个单词
    参数1=a b c d
    ===================================
    被双引号括起来的情况:$@,所有的参数被认为是各个独立的单词
    参数1=a
    参数2=b
    参数3=c
    参数4=d
    ===================================
    没有被双引号括起来的情况:$*,所有的参数被认为是各个独立的单词
    参数1=a
    参数2=b
    参数3=c
    参数4=d

八、扩展

  1. 0表示标准输入
  2. 1表示标准输出
  3. 2表示标准错误输出
  4. >默认为标准输出重定向,与1>相同
  5. 2>&1意思是把标准错误输出重定向到标准输出
  6. &>file意思是把标准输出和标准错误输出都重定向到文件file

sleep和wait

一、sleep

二、wait


各种括号

一、$()

  1. bash shell中,$()与反引号都可用做命令替换,用户可像在终端中输入命令一样,bash shell会自动进行替换。
  2. demo
1
2
3
4
5
version1=$(uname -r)
version2=`uname -r`

echo $version1
echo $version2

反引号比$()通用,有的版本不支持$()写法

二、${}

  1. ${}常用于变量替换(提取),一般情况下$var${var}并没有什么不一样,但是用${}会比较精确的界定变量名称的范围。

  2. 使用场景

    • 字符串提取

      • 使用通配符
        • #是去掉左边的字符串(从前往后),默认是最小匹配,##是最大匹配
        • %是去掉右边的字符串(从后往前),默认是最小匹配,%%是最大匹配
      1
      2
      3
      4
      5
      6
      7
      #!/bin/bash
      var=/dir1/dir2/dir3/dir4/a.b.txt
      echo ${var#*/} #去掉第一个/及其左边的内容:dir1/dir2/dir3/dir4/a.b.txt
      echo ${var##*/} #去掉最后一个/及其左边的内容:a.b.txt

      echo ${var%.*} #去掉最后一个.及其右边的内容:/dir1/dir2/dir3/dir4/a.b
      echo ${var%%.*} #去掉第一个.及其右边的内容:/dir1/dir2/dir3/dir4/a
      • 使用下标
      1
      2
      3
      4
      5
      6
      7
      #!/bin/bash
      var=/dir1/dir2/dir3/dir4/a.b.txt
      echo ${var:0:5} #从下标0开始,取字符长度为5,得到:/dir1
      echo ${var:5:5} #从下标5开始,取字符长度为5,得到:/dir2
      echo ${var:5} #从下表5开始,取到字符串末尾,得到:/dir2/dir3/dir4/a.b.txt
      echo ${var: -5} #从下表-5开始,取到字符串末尾,得到:/dir2/dir3/dir4/a.b.txt
      echo ${var:(-5)} #从下表-5开始,取到字符串末尾,得到:/dir2/dir3/dir4/a.b.txt
    • 字符串替换

      1
      2
      3
      4
      #!/bin/bash
      var=/dir1/dir2/dir3/dir4/a.b.txt
      echo ${var/dir/directory} #将第一个dir替换为directory,得到:/directory1/dir2/dir3/dir4/a.b.txt
      echo ${var//dir/directory} #将所有的dir替换为directory,得到:/directory1/directory2/directory3/directory4/a.b.txt
    • 针对变量不同状态赋值(没设定、空值、非空值)

      • ${var:-string}:若变量var为空则用string来替换${var:-string},否则变量var不为空时,则用变量var的值来替换${var:-string}

      • ${var:=string}:若var为空时则用string替换${var:=string}的同时,把string赋给变量var

        • ${var:=string}很常用的一种用法是判断某个变量是否赋值,没有的话则给它赋上一个默认值。
      • ${var:+string}的替换规则和上面的相反,即只有当var不是空的时候才替换成string,若var为空时则不替换或者说是替换成变量var的值,即空值。

      • ${var:?string}替换规则为:若变量var不为空则用变量var的值来替换${var:?string};若变量var为空则把string输出到标准错误中,并从脚本中退出。

        • 可利用此特性来检查是否设置了变量的值。
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        #!/bin/bash
        var=/dir1/dir2/dir3/dir4/a.b.txt

        echo ${var-test.txt}
        echo ${file1-test.txt}

        echo ${var:-test.txt}
        echo ${file2:-test.txt}

        echo ${var+test.txt}
        echo ${file3+test.txt}

        echo ${var:+test.txt}
        echo ${file4:+test.txt}

        echo ${var=test.txt}
        echo ${file5=test.txt}

        echo ${var:=test.txt}
        echo ${file6:=test.txt}

        echo ${var?test.txt}
        echo ${file7?test.txt}

        echo ${var:?test.txt}
        echo ${file8:?test.txt}
    • 取变量长度

      • 取字符串长度
      1
      2
      3
      #!/bin/bash
      str=123456
      echo ${#str}
      • 取数组元素个数
      1
      2
      3
      4
      #!/bin/bash
      arr=(a b c)
      echo ${#arr[@]}
      echo ${#arr[*]}

三、[]和[[]]

  1. []完全等价于命令test,可用于测试表达式,常见如字符串比较,算术比较,文件等。

    • 文件检测
      • 文件类检测
        • -e file:文件是否存在(exist)
        • -f file:文件是否存在且为普通文件(file)
        • -d file:文件是否存在且为目录(directory)
        • -b file:文件是否存在且为块设备(block device)
        • -c file:文件是否存在且为字符设备(character device)
        • -S file:文件是否存在且为套接字文件(Socket)
        • -p file:文件是否存在且为命名管道文件FIFO(pipe)
        • -L file:文件是否存在且是一个链接文件(Link)
      • 文件属性检测
        • -r file:文件是否存在且当前用户可读
        • -w file:文件是否存在且当前用户可写
        • -x file:文件是否存在且当前用户可执行
        • -u file:文件是否存在且设置了SUID
        • -g file:文件是否存在且设置了SGID
        • -k file:文件是否存在且设置了sbit(sticky bit)
        • -s file:文件是否存在且大小大于0字节,即用于检测文件是否为非空白文件
        • -N file:文件是否存在,且自上次read后是否被modify
      • 两个文件之间的比较
        • file1 -nt file2:判断file1是否比file2新,即newer than
        • file1 -ot file2:判断file1是否比file2旧,即older than
        • file1 -ef file2:判断file2与file2是否为同一文件,可用在判断hard link的判定上。主要意义在判定,两个文件是否均指向同一个分区上的同一个inode,即equal file
    • 数值检测(支持正负整数,不支持浮点数)
      • int1 -eq int2:两数值相等(equal)
      • int1 -ne int2:两数值不等(not equal)
      • int1 -gt int2:int1大于int2(greater than)
      • int1 -lt int2:int1小于int2(less than)
      • int1 -ge int2:int1大于等于int2(greater than or equal)
      • int1 -le int2:int1小于等于int2(less than or equal)
    • 字符串检测
      • -z string:判定字符串是否为空(zero),为空则返回true。
      • string-n string:判定字符串是否非空,为空则false。
        • 注:-n可省略
      • string1 = string2string1 == string2:string1和string2是否相同,相同则返回true。
        • ===等价,但=可移植性更好
      • str1 != str2:str1是否不等于str2,不等则返回true。
      • str1 > str2:str1字母顺序是否大于str2,大于则返回true。
      • str1 < str2:str1字母顺序是否小于str2,小于则返回true。
    • 逻辑检测
      • -a&&:两表达式同时为true时才为true。
        • -a只能在test[]中使用,&&只能在[[]]中使用
      • -o||:两表达式任何一个true则为true。
        • -o只能在test[]中使用,||只能在[[]]中使用
      • !:对表达式取反
      • ():用于改变表达式的优先级,为了防止被shell解析,应该加上反斜线转义\( \)
  2. 知识点

    • 使用[][[]]时必须有空格,这是强制要求的格式。
    • test命令使用标准的数学比较符号来表示字符串的比较,而用文本符号来表示数值的比较。
    • 大于符号或小于符号必须要转义,否则会被理解成重定向。

四、(())及[[]]

  1. (())[[]]分别是[]的针对数学比较表达式和字符串表达式的加强版。
    • [[]]中增加模式匹配特性。
    • (())不需要再将表达式里面的大小于符号转义,另新增了++、–、~、&、|、**、<<、>>、!、&&、||等运算。

五、参考

  1. 参考一

基本运算符

一、算术运算符

  1. 原生bash不支持简单的数学运算,但是可以通过其他命令来实现,如awkexpr

  2. 知识点

    • 表达式和运算符之间要有空格,这点很重要
      • =作为算术运算符的赋值运算时不能有空格
    • 完整的表达式要被反引号(``)包含
    • 加(+)、减(-)、乘(*)、除(/)、取余(%)、赋值(=)、相等(==)、不相等(!=)运算
      • 乘法运算注意转义字符的使用,如用expr 2 \* 2为正确写法,expr 2 * 2则会报错
      • 相等运算符(==)可用于比较字符串是否相等(作用和字符串运算符=相同)
  3. demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
num1=2
num2=3
echo `expr $num1 \* $num2`

a=$1
b=$2
echo $a,$b

if [ "$a" = "$b" ]
then
echo "equal"
else
echo "not equal"
fi

if [ "$a" == "$b" ]
then
echo "equal"
else
echo "not equal"
fi

二、关系运算符

  1. 关系运算符只支持数字,不支持字符串(除非字符串的值是数字)。
    • 算术运算符的==和字符串运算符的=!=可以实现字符串相等、不相等比较
  2. 相等(-eq)、不相等(-ne)、大于(-gt)、大于等于(-ge)、小于(-lt)、小于等于(-le)
  3. demo
1
2
3
4
5
6
7
8
a=10
b=20
if [ $a -eq $b ]
then
echo "equal"
else
echo "not equal"
fi

三、布尔运算符

  1. 布尔运算符需要使用单中括号[]
  2. 非运算(!)、或运算(-o)、与运算(-a)

四、逻辑运算符

  1. 逻辑运算符和布尔运算符有点相似(从理解上),使用时需要用双中括号[[]]
  2. 逻辑与(&&)、逻辑或(||)

布尔运算符和逻辑运算符区别

  • 使用上,布尔运算符使用单中括号[],逻辑运算符使用双中括号[[]],不能混用
  • 功能上,逻辑运算符会发生短路作用,布尔运算符则不会
  1. demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/bin/bash

a=10
b=20

echo "====逻辑与运算===="
if [[ $a -lt 100 && $b -gt 100 ]]
then
echo success
else
echo fail
fi

echo "====逻辑或运算===="
if [[ $a -lt 100 || $b -gt 100 ]]
then
echo success
else
echo fail
fi

echo "====布尔与运算===="
if [ $a -lt 100 -a $b -gt 100 ]
then
echo success
else
echo fail
fi

echo "====布尔或运算===="
if [ $a -lt 100 -o $b -gt 100 ]
then
echo success
else
echo fail
fi

五、字符串运算符

  1. 字符串运算符可以实现对字符串的一些操作
    • =:检测两个字符串是否相等,相等返回true。
    • !=:检测两个字符串是否相等,不相等返回true。
    • -z:检测字符串长度是否为0,为0返回true。
    • -n:检测字符串长度是否不为0,不为0返回true。
    • $:检测字符串是否为空,不为空返回true。
  2. demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/bin/bash
a="abc"
b="acd"
echo "a=$a,b=$b"

echo ====字符串=操作====
if [ $a = $b ]
then
echo "a等于b"
else
echo "a不等于b"
fi

echo ====字符串!=操作====
if [ $a != $b ]
then
echo "a不等于b"
else
echo "a等于b"
fi

echo ====字符串-z操作====
if [ -z $a ]
then
echo "字符串a长度为0"
else
echo "字符串a长度不为0"
fi

echo ====字符串-n操作====
if [ -n "$a" ]
then
echo "字符串a长度不为0"
else
echo "字符串a长度为0"
fi

echo ====字符串\$操作====
if [ $a ]
then
echo "字符串a不为空"
else
echo "字符串a为空"
fi

六、文件测试运算符

  1. 文件测试运算符用于检测Unix(类Unix)文件的各种属性。
    • -b file:检测文件是否是块设备文件,如果是则返回true。
    • -c file:检测文件是否是字符设备文件,如果是则返回true。
    • -d file:检测文件是否是目录,如果是则返回true。
    • -f file:检测文件是否是普通文件(既不是目录也不是设备文件),如果是则返回true。
    • -g file:检测文件是否设置了SGID位,如果是则返回true。
    • -k file:检测文件是否设置了粘着位(Sticky Bit),如果是则返回true。
    • -p file:检测文件是否是有名管道,如果是则返回true。
    • -u file:检测文件是否设置了SUID位,如果是则返回true。
    • -r file:检测文件是否可读,如果是则返回true。
    • -w file:检测文件是否可写,如果是则返回true。
    • -x file:检测文件是否可执行,如果是则返回true。
    • -s file:检测文件是否为空(文件大小是否大于0),不为空返回true。
    • -e file:检测文件(包括目录)是否存在,如果是则返回true。
    • -S file: 判断某文件是否socket,如果是则返回true。
    • -L file: 检测文件是否存在并且是一个符号链接,如果是则返回true。
  1. demo

    • ls -al ./test.sh,得到结果-rwxr-xr-x 1 yourname staff 12 5 31 01:09 ./test.sh
    • 脚本
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    #!/bin/bash
    file="./test.sh"

    if [ -r $file ]
    then
    echo "文件可读"
    else
    echo "文件不可读"
    fi

    if [ -w $file ]
    then
    echo "文件可写"
    else
    echo "文件不可写"
    fi

    if [ -x $file ]
    then
    echo "文件可执行"
    else
    echo "文件不可执行"
    fi

    if [ -f $file ]
    then
    echo "文件为普通文件"
    else
    echo "文件为特殊文件"
    fi

    if [ -d $file ]
    then
    echo "文件是个目录"
    else
    echo "文件不是个目录"
    fi

    if [ -s $file ]
    then
    echo "文件不为空"
    else
    echo "文件为空"
    fi

    if [ -e $file ]
    then
    echo "文件存在"
    else
    echo "文件不存在"
    fi

    if [ -S $file ]
    then
    echo "是socket文件"
    else
    echo "不是socket文件"
    fi

    if [ -L $file ]
    then
    echo "是链接文件"
    else
    echo "不是链接文件"
    fi

七、总结

  1. 布尔运算符-a-o只能在test[]中使用,逻辑运算符&&||只能在[[]]中使用。
  2. 注意区分=!=在不同脚本时所代表的运算符种类