高级语言、脚本语言、解释型语言:xxx.sh,一般基于 bash
课程内容#
第一个 Shell 脚本#
#!/bin/bash
#注释
echo "Hello"
- 第一行 #! 指定解释器,只在第一行才有效
- 注释:"#"
变量#
a=123
a=hello
a=`pwd`
PATH=${PATH}:path # 变量后接字符串,可以直接拼接字符串
# 【注意】":a"有特殊含义,会指到当前路径
特殊变量#
位置变量
结果:
-
$n:如果 n>9,需要用大括号括起来
-
$@ 和 $* 的区别在于:传入参数分别被双引号包围、且 $ 变量也被双引号包围时,"$@" 会将所有的参数分开【一般情况】,而 "$*" 会将所有的参数作为一个整体
- 在用 for...in 时可以看出,详见 Shell 特殊变量:Shell $0, $#, $*, $@, $?, $$ 和命令行参数——C 语言中文网
-
$#:不算 $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
-
if 用两个中括号 [[]] 的写法,更高级,与 TEST 表达式兼容性更好
- 而一个中括号 [ ] 是很多年前的写法,不推荐,两个中括号
- 参考Linux Shell 中 ()、(())、[]、[[]]、{} 的作用—— 博客
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
素数筛#
-
方式一方便操作素数,且输出时可减少判断
-
方式二还可以操作合数
【暴力法、素数筛 2 种方法效果比较】求 2~10000 的素数和
- 9.prime.sh 暴力法 —— 10.prime.sh 素数筛
附加知识点#
- .sh 脚本可以直接 bash 或 source 执行,如果要使用./ 需要有可执行权限
- source、sh、bash、./ 有什么区别——cnblogs
- 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—— 菜鸟教程,方便的语法