7 Shell编程基础

高级语言、脚本语言、解释型语言:xxx.sh,一般基于bash

课程内容

第一个Shell脚本

#!/bin/bash
#注释
echo "Hello"
  • 第一行#!指定解释器,只在第一行才有效
  • 注释:"#"

变量

a=123
a=hello
a=`pwd`
PATH=${PATH}:path  # 变量后接字符串,可以直接拼接字符串
# 【注意】":a"有特殊含义,会指到当前路径
  • 不需要定义变量类型【弱类型语言】
    • 如a=123可以是字符串,也可以是整数
  • ":a"有特殊含义
    • img
    • 可用双引号包住a,如a=$a:"a"或a=$a":a",得到a=123:a

特殊变量

位置变量

  • image-20201218170251055

结果:

  • image-20201215174953312
  • $n:如果n>9,需要用大括号括起来

  • $@ 和 $* 的区别在于:传入参数分别被双引号包围、且$变量也被双引号包围时,"$@" 会将所有的参数分开【一般情况】,而"$*" 会将所有的参数作为一个整体

  • $#:不算$0

状态变量

  • $?:【上一条】指令执行结果,0——成功,非0——不成功
    • 图片
    • 便于脚本自动判断指令成功与否
  • $$、$!:当前进程、最后运行的后台进程的PID,一般用于自动化测试、多脚本交互场景

输入输出

  • 输入:read
    • 图片
    • -p:显示友好提示,需在bash下使用
    • -s:静默模式
    • -t:输入等待时长,超时结束(单位:s)
  • 输出:echo
    • -e:开启转义
  • 输出:printf
    • 和C语言的printf非常像!
    • 图片
    • [PS] !和\n放一起有特殊含义,需要分开
      • bash下需要分开
      • zsh下可以分开,或用\转义
      • 一般对于特殊符号——菜鸟教程,需要警觉!

函数

  • 图片
  • 没有形参

  • 定义:写法很多,function、()、{}组合搭配,第3种更类似C语言写法

  • 调用:函数名 参数...

    • 图片
    • 加function方便阅读
  • ❗【注意】shell中函数return的返回值有限制,范围是0-255,溢出会循环换算

流程控制

do——done、if——then——fi、case——esac

【重点】TEST表达式⭐

  • 可判断类型:字符串、整型、文件
  • ❗ 【注意】条件为真时,返回0,否则返回非0
    • Linux中命令的返回值也是如此,0才代表成功
  • [PS]
    • STRING1 = STRING2 也可以用== 【推荐后者,两个中括号[[ ]]支持】
    • -G FILE:文件存在并且被有效组ID拥有
      • 如果组被解散了,则组控制的文件的组ID就是无效的
    • 具体可查阅man手册:man test

分支结构

if

case

  • 图片
  • 分号;;不能没有!相当于break,加了break也要有

  • 默认情况可用*)

  • case用的较少,一般用来做菜单,比if更美观

循环结构

for

  • 利用seq生成序列

  • 图片
  • 利用ls的匹配规则

  • 图片
  • for的两种形式

  • 图片
  • 双小括号(())中的内容只要符合C语言运算规则即可,变量可以不使用变量前缀$,可以写i++,平常不可以用++

while

  • 图片
  • 同样适用test表达式

  • 初始化num变量,否则

    • 第一次echo $num时,$num是空值,表现为空行
    • 当遇到后面的+1时,系统判定它为整数类型,才当做整数用

until

  • 图片
  • 与while唯一的区别在于:until写的是停止条件,while写的是循环条件

数组

  • 图片
  • 数组赋值【方式①】和调用

  • 图片
  • 【常用的数组操作】还可以输出数组元素的下标,见后

  • 图片
  • 声明数组:declare -a num,方便阅读,不声明也可以 [弱类型语言]

  • 赋值【方式②、③】

    • num[2]=10 num[5]=7 num[100]=3.2.4
    • num=(1 a b 10)
  • 数组元素不一定要连续赋值,且可以为任意类型

    • 【常用的数组操作】加!:输出所有数组元素对应的下标,可以看出不是连续的

【其它数组操作】

  • 图片
  • +=:追加

  • unset:删除数组,或元素 [通过下标删除]

  • [PS] 赋值方式③对多个空格也只作一个分隔符

应用

  • 图片
  • 可以用来存储文件名列表

  • 【注意】赋值方式③给数组赋值是以空格作为分隔符,所以如果文件名里有空格,需要特殊处理

  • 【PS】素数筛、线性筛

随堂练习

1~100的偶数和

  • 图片
  • $[ ]可用来做整数运算

  • seq效率稍低

暴力求素数

  • 图片
  • 函数的return值

    • 通过$?获得,在调用函数后echo $?即可,但是return值有范围限制0~255!
    • 通过命令替换符``取到
  • 注意对于循环变量i的冲突问题:定义局部变量

  • 🆒调试程序

    • 习惯:适当的echo输出
    • 全局调试:bash -x *.sh
    • 局部调试:set -x [调试代码区域] set +x

素数筛

  • img
  • 方式一方便操作素数,且输出时可减少判断

  • 方式二还可以操作合数

【暴力法、素数筛2种方法效果比较】求2~10000的素数和

img
  • 9.prime.sh 暴力法 —— 10.prime.sh 素数筛

附加知识点

  • .sh脚本可以直接bash或source执行,如果要使用./需要有可执行权限
  • set -x可以开启shell调试
  • Shell命令替换:将命令的输出结果赋值给变量——C语言中文网
    • $() 支持嵌套,反引号``不行
    • $() 仅在 Bash 中有效 [似乎zsh、sh都支持],而反引号``可在多种 Shell 中使用
  • 双小括号(())中的内容
    • 只要符合C语言运算规则即可
    • 变量可以不使用变量前缀$
    • 可以写i++,平常不可以用++
  • ⭐在Shell中,变量还未定义时,其值为空,echo输出表现为空行
  • ⭐空格问题【严格】
    • 赋值语句:=左右不能有空格
    • TEST表达式相关:[[ ]]两端必须有空格
  • 对于变量名i,如果想将$i与_i拼接,用$i_i,会去找变量i_i,所以要用${i}_i

Tips

  • 写Shell脚本
    • 不要太考虑性能,单纯做数学计算效率低
    • 为的是快速解决一个问题,用来规划所有任务的流程
    • 做操作前记得加【备份】操作
    • 一般是让系统做事情,难于操作特定的程序做事情
      • 程序一般有自己的参数设置,但不具有普适性
  • API一般指服务
  • Shell 风格指南——Google 开源项目风格指南——Shell编程规范
  • Shell脚本多行注释和单行注释的方法——博客
:<<!
[要注释的代码]
!
  • 可以了解let——菜鸟教程,方便的语法

课程速记

  • 图片
  • 图片
  • 图片