ShellScript学习笔记
- 概述
- 常用命令
1. 概述
ShellScript 指批处理脚本(能被 shell 执行,其中 bash 用的最多)
ShellScripy 脚本文件通常以.sh 结尾,赋予执行权限后可以直接用名字调用
1.1 注释
在第一行,可以指定执行该脚本的 shell,如:
1 | !/bin/bash |
除了第一行,以#开始到该行结束为注释
1.2 返回值
在 Shell 中,执行完一个命令,文件,程序之后,会返回给 shell 一个返回值,可以通过$?
查看该返回值
1.3 规范
参考自<<鸟哥的 Linux 私房菜—基础篇>>
在 shellscript 的前面,可以添加一些该文件的信息
- script 的功能
- 版本信息
- 作者和联系方式
- 版权相关(包括开源协议等)
- 特殊备注等
1.4 执行方法
./shell.sh
shell 开启一个子进程,执行该脚本后再返回 shellsource ./shell.sh
shell 直接在本身的进程中执行该脚本
其产生的效果和变量会保留在 shell 的环境中
2. 常用命令
ShellScript 中没有函数,但是可以用一些命令来代替常用的函数$(command)
可以获取命令执行的结果(可以赋值给变量)
2.1 输入输出
- read : 从键盘输入
- echo : 输出到标准输出
- printf:
printf 是一个仿照 C 标准库的命令
printf format-string [arguments…]
2.2 时间日期
- data : 日期类(动态生成日期)
- time : 统计命令执行时间
2.3 数值类
- ${RANDOM} : 特殊变量,生成一个 0~32767 的随机数
- bc : basic calculator,用于科学计算
3. shell 语法
3.1 变量
3.1.1 普通变量
- 声明
直接使用var=666
格式声明即可
重新赋值也是直接用这个格式就行了
声明后可以使用 readonly 关键字指定其为只读:readonly var
- 运算
使用$((表达式))
即可对表达式进行计算
使用${label}
可以引用变量
支持+ - * / %
运算符
还可以使用bc
或者expr
命令提供的小数计算 - 删除
unset label
- 命令行参数
$0
:脚本绝对路径名称$0--
:命令行参数$#
:命令行参数个数$@
:相当于"$1","$2"...
,即所有参数的集合$*
:相当于"$1 $2 $3..."
,即以空格分割的所有参数的集合
使用 shift [count]命令可以移除命令行参数(即消去前 count 个参数)
3.1.2 字符串变量
字符串变量有两种声明方式:
- 单引号: ‘string’
- 双引号: “string”
单引号变量中任何字符都会原样输出(不可使用变量和转义字符)
双引号中的形如${label}
会被解析为变量
- 获取字符串长度:
${\#string}
(这个井号把 hexo 搞崩了…找了好久才找出来是这个井号)expr length ${string}
- 字符串拼接:
直接拼在一起就行(包括变量),如"string1"${string}"String"
- 查找子字符串:
使用 expr 命令进行查找
`expr index $string $substring”
3.1.3 数组
定义
var=("111" 222 333 "444")
在 bash 中下标从 0 开始使用
指定其中的一个变量echo ${var[0]}
选取所有变量echo ${var[*]}
或者echo ${var[@]}
获取数组长度
echo ${\#var[@]}
3.2 判断表达式
3.2.1 test 指令判断
- 首先是四个逻辑判断
表达式 | 结果逻辑 |
---|---|
( 表达式 ) | 表达式为真 |
! 表达式 | 表达式为假 |
表达式 1 -a 表达式 2 | 两个表达式都是真 |
表达式 1 -o 表达式 2 | 两个表达式有一个真 |
- 然后是各种逻辑参数
参数 | 结果逻辑 |
---|---|
-n | 字符串字符串长度非零 |
STRING | 等价于 -n 字符串 |
-z 字符串 | 字符串的长度为 0 |
字符串 1 = 字符串 2 | 字符串相等 |
字符串 1 != 字符串 2 | 字符串不相等 |
整数 1 -eq 整数 2 | 整数 1 与整数 2 相等 |
整数 1 -ge 整数 2 | 整数 1 大于或等于整数 2 |
整数 1 -gt 整数 2 | 整数 1 大于整数 2 |
整数 1 -le 整数 2 | 整数 1 小于或等于整数 2 |
整数 1 -lt 整数 2 | 整数 1 小于整数 2 |
整数 1 -ne 整数 2 | 整数 1 和整数 2 不相等 |
文件 1 -ef 文件 2 | 文件 1 和文件 2 拥有相同的设备编号与 inode 编号 |
文件 1 -nt 文件 2 | 文件 1 在修改时间上新于文件 2 |
文件 1 -ot 文件 2 | 文件 1 比文件 2 更旧 |
-b 文件 | 文件存在且为块特殊文件 |
-c 文件 | 文件存在且为字符特殊文件 |
-d 文件 | 文件存在且为目录 |
-e 文件 | 文件存在 |
-f 文件 | 文件存在且为普通文件 |
-g 文件 | 文件存在且被设置了 set-group-ID 位 |
-g 文件 | 文件存在且为有效组 ID 所有 |
-h 文件 | 文件存在且为一个符号链接(与 -L 相同) |
-k 文件 | 文件存在且被设置粘着位 |
-L 文件 | 文件存在且为一个符号链接(与 -h 相同) |
-O 文件 | 文件存在且为有效用户 ID 所有 |
-p 文件 | 文件存在且为命名管道 |
-r 文件 | 文件存在且被授予读权限 |
-s 文件 | 文件存在且其大小大于零 |
-S 文件 | 文件存在且为套接字 |
-t FD | 文件描述符 FD 在某个终端打开 |
-u 文件 | 文件存在且被设置了 set-user-ID 位 |
-w 文件 | 文件存在且被赋予了写权限 |
-x 文件 | 文件存在且被授予执行(或搜索)权限 |
3.2.2 中括号判断表达式
- 文件判断参数 [ options file ]
参数 | 结果逻辑 |
---|---|
-d | 测试文件是否为目录类型 |
-e | 测试文件是否存在 |
-f | 判断是否为一般文件 |
-r | 测试当前用户是否有权限读取 |
-w | 测试当前用户是否有权限写入 |
-x | 测试当前用户是否有权限执行 |
- 数字判断参数[ num1 options num2 ]
参数 | 结果逻辑 |
---|---|
-eq | 是否等于 |
-ne | 是否不等于 |
-gt | 是否大于 |
-lt | 是否小于 |
-le | 是否等于或小于 |
-ge | 是否大于或等于 |
- 字符串判断参数 [ options string ]
参数 | 结果逻辑 |
---|---|
= | 比较字符串内容是否相同 |
!= | 比较字符串内容是否不同 |
-z | 判断字符串是否为空 |
3.3 流控制
3.3.1 单行流控制
通用格式: command1 标志 command2
标志 | 功能 | ||
---|---|---|---|
&& | 上一条命令成功,才执行下一条指令 | ||
\ | \ | 上一条指令失败,才执行下一条指令 | |
;; | 无条件执行下一条指令 |
3.3.2 判断 & 分支
if 语句
1 | if [ 判断语句 ];then |
case 语句
1 | case ${变量} in |
3.3.3 循环语句
for 语句
for 语句中的取值列表可以为字面量1 2 3 4
,1...10
可以为变量${label}
1 | for var in 取值列表 |
还可以指定初始值,限制值和步长来处理数值
1 | for ((var=初始值;var<限制值;var=var+1)) |
while 语句
1 | while [ 判断语句 ] |
until 语句
1 | until [ 判断语句 ] |
3.4 函数
基本格式
1 | [function] funcname(){ |
- function 关键字可以省略
- 不用定义参数,而是和命令行参数一样时候用
$0 $1 ...
的形式来调用 - 只能返回整数返回值 0~255
如果没有声明 return 语句,使用最后一条命令的返回值作为返回值
导入包
1 | 实用 . 引入包 |
引入包相当于把原本包内的多有内容复制到插入点
其中定义的变量和函数都会被定义
同时其中的命令也会全部执行一遍,如果多次引入则会执行多次
4. 调试运行
直接手动在命令行里调试实在是太费劲了
vscode 有很多好用的插件可以支持 shell 的调试和运行
- Code Runner : 可以支持快速无参数运行测试文件(其实也没啥用,手动运行还能添加参数)
- Bash debug : 支持调试 Bash(断点,堆栈,变量都支持)
以上两个东西在运行的时候,需要设置TerminalKind
为integrated
(即用 vscode 内置终端运行)
否则在读取用户输入会有问题(Code Runner 在插件里设置,Bash Debug 在 launch.json 中设置)
5. 周期执行任务
5.1 在指定时间执行一个任务
以下内容来自 man 手册
at 命令 用于在指定时间执行命令
at 允许使用一套相当复杂的指定时间的方法
它能够接受在当天的 hh:mm 式的时间指定.假如该时间已过去,那么就放在第二天执行
当然也能够使用 midnight,noon,teatime(一般是下午 4 点)等比较模糊的词语来指定时间
用户还能够采用 12 小时计时制,即在时间后面加上 AM 或 PM 来说明是上午还是下午
也能够指定命令执行的具体日期,指定格式为 month day 或 mm/dd/yy 或 dd.mm.yy
指定的日期必须跟在指定时间的后面
上面介绍的都是绝对计时法,其实还能够使用相对计时法
指定格式为:now + count time-units
now 就是当前时间
time-units 是时间单位,这里能够是 minutes,hours,days,weeks
count 是时间的数量,究竟是几天,还是几小时,等等
更有一种计时方法就是直接使用 today(今天)、tomorrow(明天)来指定完成命令的时间
at [options] time
-f:指定包含具体指令的任务文件
-q:指定新任务的队列名称
-l:显示待执行任务的列表
-d:删除指定的待执行任务
-m:任务执行完成后向用户发送 E-mail
启动命令后,会进入交互命令行,输入要执行的命令后按ctrl-d
退出
5.2 周期性执行任务
以下内容来自 man 手册
crontab 命令 被用来提交和管理用户的需要周期性执行的任务,与 windows 下的计划任务类似,当安装完成操作系统后,默认会安装此服务工具,并且会自动启动 crond 进程,crond 进程每分钟会定期检查是否有要执行的任务,如果有要执行的任务,则自动执行该任务。
condtab [options]
-e: 创建/编辑定时任务
-l: 列出定时任务
-r: 删除定时任务
-u<用户名称>: 指定要设定计时器的用户名称
首次使用该命令会进入交互式界面(让选择一款编辑器)
然后给一个文件,该文件中每一行代表一个任务,手动编辑后即保存为周期性任务