Shell基础之变量、判断、逻辑控制

首先我们来看看维基关于shell的介绍

Shell(也称为壳层)在计算机科学中指“为用户提供用户界面”的软件,通常指的是命令行界面的解析器。一般来说,这个词是指操作系统中提供访问内核所提供之服务的程序。Shell也用于泛指所有为用户提供操作界面的程序,也就是程序和用户交互的层面。因此与之相对的是内核(英语:Kernel),内核不提供和用户的交互功能。

大白话就是和操作系统交互用的。我们现在用的比较多的是图形用户界面(GUI),简单易用直观的操作界面。命令行界面(CLI),是在图形用户界面得到普及之前使用最为广泛的用户界面,它通常不支持鼠标,用户通过键盘输入指令,也有人称之为字符用户界面(CUI),功能复杂但是强大。


shell种类

  • 常用shell:bash、sh、zsh
  • Windows:git bash、cygwin、xshell
  • Mac:Terminal、iTerm
    屏幕截图 2021-11-05 205237.png

变量

变量名=变量值

1
2
3
4
a=1
b=apple
c="hello world"
d='hello"树 先 生"'

这里有几点注意事项:

  • =左右不要有空格
  • 如果内容有空格,需要使用单引号或双引号
  • 双引号支持转义 $开头的变量会被自动替换

屏幕截图 2021-11-05 210616.png

变量的使用

1
2
3
echo $a
echo ${b}
echo "$c"
  • 使用 $var${var} 访问变量。后者更严谨。同时,$var_x${var}_x 是不同的
  • 变量无需定义也可以使用,引用未定义的变量,默认值为空

    预定义变量

    1
    2
    3
    4
    5
    6
    echo $PWD
    echo $USER
    echo $HOME
    echo ~
    echo $PATH
    echo $RANDOM

    特殊符号的使用

  • 双引号用于括起一段字符串值,支持 $var 形式的变量替换
  • 单引号也表示其内容是字符串值,不支持转义
  • \ 反斜线,某些情况下表示转义
  • ((a=a+3)) 是整数扩展。把里面的变量当作整数去处理
  • $(ls) 执行命令并把结果保存为变量 简写为``
  • {1..10} 等价于seq1 10,表示1到10
  • seq 1 3 10 表示生成一个1到10,步进为3

    变量类型

  • 字符串 a="xx"
  • 数字 i=1314
  • 布尔 true false
  • 数组 array=(a b c)
  • 函数 foo() { echo hello world }
  • 高于4.x的shell有hash词典功能

    数字型变量操作

  • 计算 i=1;echo $i;echo $((i+1))
    屏幕截图 2021-11-06 141837.png
  • 更新 ((i=i+1));echo $i
    屏幕截图 2021-11-06 142009.png
  • 浮点数计算 awk 'BEGIN{print 1/3}'
    屏幕截图 2021-11-06 143552.png
  • 格式化浮点数,保留小数点两位awk 'BEGIN{printf("%.2f\n",1/3)}'
    屏幕截图 2021-11-06 143830.png

    字符串的操作

  • ${value:offset} ${value:offset:length} 从变量中提取字符串
  • ${#value} 字符串长度
  • ${#array[*]}${#array[@]} 表示数组中元素的个数
  • ${value#pattern} ${value##pattern} #表示掐头
  • ${value%pattern} ${value%%pattern} %表示去尾
  • ${value/pattern/string} ${value//pattern/string} / 表示替换
  • #与## %与%% /与//的区别:最短匹配模式VS最长匹配模式
  • ${var/#Pattern/Replacement} ${var/%Pattern/Replacement}
    屏幕截图 2021-11-06 150523.png
  • AWK可以代替这些操作,推荐AWK
    屏幕截图 2021-11-06 151322.png

    例子

    1
    2
    3
    4
    5
    6
    7
    xx="1234567";
    echo ${xx:2:3};
    echo ${xx/3/c};
    echo ${xx# # *3};
    echo ${x%%5*};
    echo $xx | awk '{print substr($0,2,3)}'
    echo $xx | sed 's#3#c#g'

    布尔变量

  • true
  • false
  • 命令执行返回值$?
    • 任何命令执行都会有一个返回值
    • 0表示正确
    • 非0表示错误

      算术判断

  • [ 2 -eq 2 ]相等
  • [ 2 -ne 2 ]不等
  • [ 3 -gt 1 ]大于
  • [ 3 -ge 3 ]大于等于
  • [ 3 -lt 4 ]小于
  • [ 3 -le 3 ]小于等于
  • (())也可以表示算数比较。((10>=8))

    字符串比较

  • [ str1 = str2 ]如果两个字符串相同,则为真
  • [ str1 != str2 ]如果两个字符串不相同,则为真
  • [ -n "$var" ]如果字符串不是空,则为真
  • [ -z "$var" ]如果字符串是空,则为真
  • [[ "xxxx" == x* ]]在表达式中表示0或者多个字符
  • [[ xxx == x?? ]]在表达式中表示单个字符
  • 在引用变量的时候要记得加双引号[ -z "$a" ],否则当a未定义时会报语法错误

    逻辑判断

  • [ 2 -ge 1 -a 3 -ge 4 ];echo $?
  • [[ 2 -ge 1 && 3 -ge 4 ]];echo $?
  • [ 2 -ge 1 -o 3 -ge 4 ];echo $?
  • [[ 2 -ge 1 || 3 -ge 4 ]];echo $?
  • [ ! 2 -ge 1 ];echo $?

    内置判断

  • -e file文件存在,则为真
  • -d file文件是一个子目录,则为真
  • -f file文件是一个普通文件,则为真
  • -r file文件可读,则为真
  • -s file文件长度不为0,则为真
  • -w file文件可写,则为真
  • -x file文件可执行,则为真
  • [[]][]的扩展语法,在老sh里面不支持,推荐用后者

    数组变量

  • array=(1 3 4 6)
  • array=('ls')
  • array[2]="hello world"
  • echo ${array[2]}
  • echo ${array[*]}
  • echo ${#array[*]}
  • 使用()来定义数字变量,中间使用空格分开

屏幕截图 2021-11-06 181933.png


逻辑控制

  • 条件 if
  • 分支 caseselect
  • 循环 forwhileuntil
  • breakcontinue
  • 常用的有ifforwhile

    if结构

  • if [condition ];then ...;fi
  • if [condition ];then ...;else ...;fi
    屏幕截图 2021-11-09 163526.png
  • if [condition ];then ...;elif ...;fi
  • 简单的逻辑可以使用 && ||代替
  • [ -f file ] && echo file exist || echo file not exist
    屏幕截图 2021-11-09 163752.png
  • 条件可以用命令返回值代替

    for循环

  • for((c1;c2;c3));
  • do
  • ...;
  • done
  • for((i=0;i<10;i++));do echo $i;done
    屏幕截图 2021-11-09 165214.png

    for遍历循环

  • 用于递归数组,还可以递归以空格隔开的字符串序列。或者是某个命令的返回值。
  • for f in $array[*];
  • do
  • ...
  • done
    屏幕截图 2021-11-09 165945.png
  • ss="aa bb cc";for x in $ss;do echo$x;done
  • for x in 'ls';do echo $x;done
  • ss=(aa bb cc "sss dd");for x in "${ss[@]]}";do echo $x;done
    屏幕截图 2021-11-09 170203.png

    while循环

  • while需要设置条件
  • i=0;
  • while((i<10));do
  • echo $i;((i+=1));
  • done
    屏幕截图 2021-11-09 172218.png
  • 一行行的读取文件内容while read line;do echo $line;done < /home/lighthouse/joplin/1
    屏幕截图 2021-11-09 172459.png

    退出控制

  • return 函数返回
  • exit 脚本进程退出
  • break 退出当前循环
  • continue 跳出当前循环,进入下一次循环

小实战:抽奖程序

要求:从名单中抽出一个中奖者

1
2
3
4
5
6
7
8
seeds=$(while read line;do echo ${line// /..};done < 名单.txt)
while true
do
seeds=$(for line in $seeds;do ((RANDOM%2==1)) && echo $line;done)
echo $seeds
count=$(echo "$seeds" | wc -l )
((count==1)) && break
done