您的位置:首页 > 运维架构 > Shell

SHELL脚本编程知识点

2020-08-18 19:36 826 查看

文章目录

  • 2.变量
  • 位置变量(重点)
  • 退出状态码变量
  • 展开命令执行顺序
  • 算术运算
  • 条件测试命令
  • 数值测试
  • 算术表达式比较:
  • 短路或取反
  • 环境配置文件
  • 4.流量控制,if,else语句
  • 5.条件判断case语句
  • 6.循环
  • 函数返回值
  • 环境函数
  • 函数参数
  • 函数变量
  • 函数递归
  • fork炸弹
  • SHELL脚本

    1.脚本调试

    检测脚本中的语法错误

    bash -n /script

    调试执行

    bash -x /script

    2.变量

    • 不能使程序中的保留字:如:if, for
    • 只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”
    • 见名知义,用英文名字,并体现出实际作用
    • 统一命名规则:驼峰命名法, studentname,大驼峰StudentName 小驼峰studentName
    • 变量名大写
    • 局部变量小写
    • 函数名小写

    2.1变量赋值:

    name='value'

    value可以是以下多种形式

    直接字串:name='root'变量引用:name="$USER"命令引用:name=`COMMAND` 或者 name=$(COMMAND)

    变量引用:

    $name${name}

    2.2显示已定义的所有变量:

    set

    2.3 删除变量

    unset name

    变量声明和赋值

    export name =VALUE
    declaree -x name =VALUE
    指定变量为环境变量,可供shell以外的程序使用

    显示所有环境变量:

    envprintenvexportdeclare -x

    只读变量

    只读变量:只能声明定义,但后续不能修改和删除
    声明只读变量:

    readonly namedeclare -r name

    查看只读变量:

    readonly [-p]declare -r

    位置变量(重点)

    位置变量:在bash shell中内置的变量, 在脚本代码中调用通过命令行传递给脚本的参数

    $1, $2, ... 对应第1个、第2个等参数,shift [n]换位置$0 命令本身,包括路径$* 传递给脚本的所有参数,全部参数合为一个字符串$@ 传递给脚本的所有参数,每个参数为独立字符串$# 传递给脚本的参数的个数注意:$@ $* 只在被双引号包起来的时候才会有差异

    清空所有位置变量
    set –

    退出状态码变量

    进程执行后,将使用变量 ?保存状态码的相关数字,不同的值反应成功或失败,? 保存状态码的相关数字,不同的值反应成功或失败,?保存状态码的相关数字,不同的值反应成功或失败,?取值范例 0-255

    $?的值为0 代表成功$?的值是1到255   代表失败

    范例:

    ping -c1 -W1 hostdown &> /dev/nullecho $?
    • 脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字
    • 如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

    展开命令执行顺序

    • 把命令行分成单个命令词
    • 展开别名
    • 展开大括号的声明({})
    • 展开波浪符声明(~)
    • 命令替换$() 和 ``
    • 再次把命令行分成命令词
    • 展开文件通配(*、?、[abc]等等)
    • 准备I/0重导向(<、>)
    • 运行命令

    防止拓展

    反斜线(\)会使随后的字符按原意解释
    范例:

    echo Your cost: \$5.00Your cost: $5.00

    加引号来防止扩展

    • 单引号(’’)防止所有扩展
    • 双引号(”“)也可防止扩展,但是以下情况例外:$(美元符号)

    变量拓展

    • `` : 反引号,命令替换
    • \:反斜线,禁止单个字符扩展
    • !:叹号,历史命令替换

    脚本安全和set

    set命令:可以用来定制shell环境
    $-变量

    • h:hashall,打开选项后,Shell 会将命令所在的路径hash下来,避免每次都要查询。通过set +h将h选
      项关闭
    • i:interactive-comments,包含这个选项说明当前的 shell 是一个交互式的 shell。所谓的交互式shell,
      在脚本中,i选项是关闭的
    • m:monitor,打开监控模式,就可以通过Job control来控制进程的停止、继续,后台或者前台执行等
    • B:braceexpand,大括号扩展
    • H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完成,例如“!!”返回上最近的
      一个历史命令,“!n”返回第 n 个历史命令

    set命令实现脚本安全(重点)

    • -u 在扩展一个没有设置的变量时,显示错误信息, 等同set -o nounset(变零为空时,进行报错)
    • -e 如果一个命令返回一个非0退出状态值(失败)就退出, 等同set -o errexit(发现错误,立即中断执行,退出)
    • -o option 显示,打开或者关闭选项
    • 显示选项:set -o
    • 打开选项:set -o 选项
    • 关闭选项:set +o 选项
    • -x 当执行命令时,打印命令及其参数,类似 bash -x

    格式化输出printf

    printf "指定的格式" "文本1"	"文本2" ...

    常用格式替换符

    替换符功能
    %s(string)字符串
    %f(ffloat)浮点格式
    %b相对应的参数中包含转义字符时,可以使用此替换符进行替换,对应的转义字符会被转义
    %cASCII字符,即显示对应参数的第一个字符
    %d,%i十进制整数
    %o八进制值
    %u不带正负号的十进制值
    %x十六进制值(a-f)
    %X十六进制值(A-F)
    %%表示%本身

    说明:%s 中的数字代表此替换符中的输出字符宽度,不足补空格,默认是右对齐,%-10s表示10个字
    符宽,- 表示左对齐
    #常用转义字符

    转义符功能
    \a警告字符,通常为ASCII的BEL字符
    \b后退
    \f换页
    \n换行
    \c压缩换行
    \r回车
    \t水平制表符
    \v垂直制表符
    \表示\本身

    范例:

    printf "%s\n" 1 2 3 41234
    printf "%f\n" 1 2 3 41.0000002.0000003.0000004.000000printf "%f.2\n"1 2 3 41.002.003.004.00
    printf "(%s)" 1 2 3 4(1)(2)(3)(4)printf"%s %s\n"1 2 3 41 23 4

    #%-10s 表示宽度10个字符,左对齐

    printf "%-10s %-10s %-4s %s \n" 姓名 性别 年龄 体重 小明 男 20 70小红 女 18 50姓名     性别     年龄   体重小明     男        20   70小红     女        18   50

    算术运算

    bash中的算术运算
    +, -, *, /, %取模(取余), **(乘方)
    乘法符号有些场景中需要转义

    实现算术运算:

    • let var=算术表达式
    • var=$[算术表达式]
    • var=$((算术表达式))
    • var=$(expr arg1 arg2 arg3 …)
    • declare –i var = 数值
    • echo ‘算术表达式’ | bc

    内建的随机数生成器变量:
    $RANDOM 取值范围:0-32767
    范例:

    生成 0 - 49 之间随机数

    echo $[$RANDOM%50]

    随机字体颜色:
    echo -en " \e[1;[[[RANDOM%7+31]"
    echo -en " \e[0m"

    增强型赋值:

    += i+=10 相当于 i=i+10(相当于i+10后重新赋值给自己)
    -= i-=j 相当于 i=i-j
    *=
    /=
    %=
    ++ i++,++i 相当于 i=i+1
    – i–,--i 相当于 i=i-1
    穿插内容:i++和++i的区别:

    i++	:先赋值然后再加++i	:先加然后赋值

    格式:

    let varOPERvalue

    范例:

    #自加3后自赋值let count+=3[root@centos8 ~]#i=10[root@centos8 ~]#let i+=20[root@centos8 ~]#echo $i30[root@centos8 ~]#j=20[root@centos8 ~]#let i*=j[root@centos8 ~]#echo $i600

    范例:
    自增,自减

    let var+=1let var++let var-=1let var --

    #重置变量
    unset

    i=1;let j=i++;echo "i=$i,j=$j"i=2 j=1i=1;let j=++i;echo "i=$i,j=$j"i=2 j=2

    逻辑运算

    true,false
    1,0
    与:&

    • 1 与 1 = 1
    • 1 与 0 = 0
    • 0 与 1 = 0
    • 0 与 0 = 0

    或:|

    • 1 或 1 = 1
    • 1 或 0 = 1
    • 0 或 1 = 1
    • 0 或 0 = 0
      非:!
    • ! 1 = 0 ! true
    • ! 0 = 1 ! false

    异或:^
    异或的两个值,相同为假,不同为真(意思是肯定有一个是假的)

    穿插异或运算

    当两个值相同时,则为假,做减法运算,输出结果为0,;当两个值不同时,则为真,做加法运算,输出两数之和。
    异或二进制
    范例:

    x=10;y=20;x=$[x^y];y=$[x^y];x=$[x^y];echo x=$x,y=$y x=20,y=10

    条件测试命令

    test或者 [ ] 或者[[ ]]
    [ -v NAME ] 变量是否定义
    [ -R NAME] 变量是否定义并且是名称引用
    [ -n NAME ] 变量是否不为空
    [ -z NAME ] 变量是否都为空
    用法:
    == 左侧字符串是否能够被右边的通配符PATTERN匹配
    =~ 左侧字符串是否能够被右边的正则表达式PATTERN匹配

    文件权限测试

    存在性测试
    -a FILE 同-e
    -e FILE 文件存在性测试,存在为真,否则为假
    -b FILE 是否存在且为块设备
    -c FILE 是否存在且为字符设备
    -d FILE 是否存在且为目录
    -f FILE 是否存在且为普通文件
    -h FILE 或 -L FILE 是否存在且为符号链接文件
    -p FILE 是否存在且为管道文件
    -s FILE 是否存在且为套接字文件
    文件权限测试:
    -r FILE 是否存在且可读
    -w FILE 是否存在且可写
    -x FILE 是否存在且可执行
    u FILE 是否存在且拥有SUID
    -g FILE 是否存在且拥有GUID
    -k FILE 是否存在且拥有sticky
    文件属性测试
    -s FILE 是否存在且非空
    -t fd fd文件描述是否存在在某终端已经打开
    -N FILE 文件自从上一次被打开后是否被修改过
    -O FILE 当前有效用户是否为文件属主
    -G FILE 当前有效用户是否为文件属组
    FILE1 -ef FILE2 文件1是否是文件2的硬链接
    FILE1 -nt FILE2 文件1是否新于文件2
    FILE1 -ot FILE2 文件1是否旧于文件2

    ()和{}

    都可将多个命令组合到一起批量执行
    ()在子进程中进行,不会影响当前环境
    {}在当前shell中进行,影响单签环境

    组合测试条件

    [ expressio1 -a expressio2 ]并且,expressio和expressio2都是真,结果才是真,
    [ expressio1 -o expressio2 ]或者expressio1和expressio2只要有一个是真,为真
    [! expressio] 取反
    (-a和-o需要使用测试命令进行,[[ ]]不支持)
    eg:

    ll /etc/data/scripts/disk.sh-rw-r--r--. 1 root root 349 Aug  8 10:03 disk.sh[ -f /data/scripts/disk.sh -a  -o /data/scripts/disk.sh ];echo $?1[ -f /data/scripts/disk.sh -a  -O /data/scripts/disk.sh ];echo $?

    通配符eg:

    FILE="a";echo $FILEa[[ $FILE == a* ]];echo $?0---------------------------------FILE="ba";echo $FILEba[[ $FILE == a* ]];echo $?1

    ([[ ]]中如果不想使用配配符*,只想表达*本身,可以用“”引起来,也可用\)

    正则表达式eg:

    合理的考试成绩0-100

    数值测试

    大:greater
    小:less
    于:than
    等:equal
    -eq 是否等于
    -ne是否不等于
    -gt 是否大于
    -ge 是否大于等于
    -lt 是否小于
    -le 是否小于等于

    算术表达式比较:

    == 相等
    != 不相等
    <=
    >=
    <=
    >
    <

    短路或取反

    CMD1 && CMD2 对了继续,错了终止
    CMD1 || CMD2 对了终止,错了继续
    (并且正常逻辑是&&和||混合使用,&&要在前,||放在后面)

    使用read命令来接受输入

    read [options] [name]
    eg:

    read NAME AGE HIGHTgaga 22 180echo $NAME $AGE $HIGHTgaga 22 180

    参数:
    -p 指定要显示的提示
    -s 静默输入,一般是口令输入
    -n -N 指定输入的字符长度
    -d ‘字符’ 输入结束符
    -t N TIMEOUT为N秒
    接受重定向:12345>abc,a=1,b=2,c=345

    环境配置文件

    1.分类

    按照生效范围可分为两类
    全局:
    /etc/profile
    /etc/profile.d/*.sh
    /etc/bashrc
    个人:
    ~/.nash_profile
    ~/.bashrc

    2.功能分类

    profile类为交互式登录的shell提供配置,常规用于定义环境变量,运行命令或脚本
    bashrc类为非交互式登录的shell提供配置,常规用于定义别命名和函数,定义本地变量

    3.Bash退出任务

    保存在~/.bash_logout文件中(用户),在退出登录时运行。

    • 创建自动备份
    • 清除临时文件

    4.流量控制,if,else语句

    format:
    单分支:
    i

    ifthenfi

    双分支:

    ifthenelsefi

    多分支:

    ifthenelifthenelifthen...elsefi

    5.条件判断case语句

    format:

    case $NAME inpattern)CMD;;pattern)CMD;;esac

    case支持glob风格的通配符

    •   任意长度字符

    ? 任意单个字符
    [ ] 指定范围内的任意单个字符
    | 或者,如:a|b

    6.循环

    循环次数已知
    循环次数未知
    format:
    1.

    for A in list;do循环体done

    for A in list
    do
    循环体
    done
    (page63)

    格式2

    双小括号方法即((…))格式,也可以用于算术运算,双小括号方法也可以使用bash shell实现c语言风格的变量操作
    i=10;((i++))

    for((:for((exp1;exp2;exp3)));docmddone
    for((控制变量初始化;条件判断表达式;控制变量的修正表达式))do循环体done
    • 控制变量初始化,仅在运行到循环代码段时执行一次
    • 控制变量的修正表达式:每轮循环结束都会先进性控制变量的修正运算,而后在做条件判断。

    while循环

    格式:while CMD;do;CMD;done
    while condition;do 循环体;done
    dondition:循环控制条条件:进行入循环前先做一次判断;
    每一次循环之后会再次做判断,条件为true时,则执行一次循环,直到条件测试为false时终止循环。

    until

    格式:until cmd;do;cmd;done
    until condition;do
    循环体
    done
    进入条件:condition为false
    退出条件:comdition为true
    当值为false时,执行循环

    循环控制语句continue

    continue
    :提前结束第N层的本轮循环,而进入一轮判断;最内层为第1层。
    格式:
    while condition ;do
    cmd1

    if condition2;then
    conitue
    fi
    cmdn

    done
    continue是不执行满足条件判断这次循环

    循环控制语句break

    break是直接中断后面所有循环。
    外循环(
    内循环(
    break n (当break值为1时,中断内循环)(当值为2时,内循环执行到满足场景时中断,外部只执行一次)

    循环控制shift命令

    shift用于将参量列表list左移指定次数,缺省为左移一次。
    参量列表list一旦被移动最左端那个参数就从列表中删除。while循环遍历位置参量列表时,常用到while

    while特殊用法:while read

    while循环的特殊用法,遍历文件或文本的每一行
    格式:
    while read line ;do
    循环体
    done < /path/from/somefile
    依次读取/path/from/somefile文件中的每一行,且将赋值给变量line。

    循环与菜单select

    格式:
    select name [in words…;] do cmd;done
    select variable in list ;do
    循环体命令
    done
    说明:
    select循环主要用于创建菜单,按数字顺序排列的菜单显示在标准的错误上,并显示PS3提示符号,等待用户输入。

    函数function

    函数function是由若干条shell组成的语句块,实现代码重用和模块化编程,它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分。

    #语法一:func_name(){...函数体...}#语法二:function func_name{...函数体...}#语法三:function func_name(){...函数体...}

    查看函数
    #查看当前已定义的函数名
    declare -F
    #查看当前已经定义的函数定义
    declare -f
    #查看指定当前已定义的函数名
    declare -f func_name
    #查看当前已定义的函数名定义
    declare -F func_name
    #删除函数
    unset func_name

    函数调用

    函数的调用方式

    可在交互环境下定义函数

    可将函数放在脚本文件中作为它的一部分

    可放在只包含函数的单独文件中

    调用:函数只有被调用才会执行,通过给定函数名调用函数。
    在交互式环境中可已使用函数
    在脚本中定义及使用函数
    函数在使用前必须定义,因此应将函数定义放在脚本开始部分,直至shell首次发现它之后才能使用,调用函数仅使用其函数名即可。

    使用函数文件

    可以将经常使用的函数存入一个单独的函数文件,然后将函数文件载入shell,再进行调用函数文件名可以任意取,但最好与相关任务有某种联系。例如,functions
    一旦函数文件载入shell,就可以在命令行或脚本中调用函数。可以使用declare -f 或者set命令查看所有定义的函数,其输出列表包括已经载入的shell的所有函数。
    若要改动函数,首先unset命令从shell中删除函数。改动完毕后,再重新载入此文件。
    在shell脚本或交互式中调用函数,格式如下:

    . /filename 或source filename

    函数返回值

    函数的执行结果返回值:
    使用echo等命令进行输出
    函数体中调用命令的输出结果
    函数的退出状态码:
    默认取决于函数中执行的最后一条命令的退出状态码
    自定义退出状态码,其格式为:
    return ,从函数中返回,用最后状态命令决定返回值
    return 0 无错误返回
    return 1-255 有错误返回

    环境函数

    类似于环境变量,也可以定义环境函数,使子进程也可以使用父进程定义的函数
    定义环境函数:
    export -f function_name
    declare -xf function_name
    查看环境函数:
    export -f
    declare -xf

    函数参数

    函数可以接受参数:

    • 传递参数给函数:在函数名后面可以空白分隔给定参数列表即可,如testfunc arg1 arg2 …
    • 在函数体中,可使用$1,$2,…调用这些参数;还可以使用$@$*$#等特殊变量
      eg:

    函数变量

    变量作用域:

    • 普通变量:只有在当前shell进程有效,为执行脚本会启动专用子进程;因此,本地变量的作用范围是当前shell脚本程序文件,包括脚本中的函数。
    • 环境变量:当前shell和子shell有效
    • 本地变量:函数的生命周期;函数结束时变量被自动销毁

    注意:

    • 如果函数中定义了普通变量,且名称和局部变量相同,则使用本地变量
    • 在函数中使用本地变量的方法

    local name=value

    函数递归

    函数递归:函数直接或间接调用自身,注意递归层数,可能会陷入死循环

    fork炸弹

    fork炸弹是一种恶意程序,他的内部是一个不断循环的递归程序,急速耗尽内存资源:

    :(){:|:&};:
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: