1. 概述
  2. 常用命令

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 开启一个子进程,执行该脚本后再返回 shell
  • source ./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
2
3
4
5
6
7
if [ 判断语句 ];then
command
elif [ 判断语句 ];then
command
else
command
fi
case 语句
1
2
3
4
5
6
7
8
9
10
11
case ${变量} in
条件范围)
command
;;
条件范围)
command
;;
*)
command
;;
esac

3.3.3 循环语句

for 语句

for 语句中的取值列表可以为字面量
1 2 3 4,1...10
可以为变量
${label}

1
2
3
4
for var in 取值列表
do

done

还可以指定初始值,限制值和步长来处理数值

1
2
3
4
for ((var=初始值;var<限制值;var=var+1))
do
command
done
while 语句
1
2
3
4
while [ 判断语句 ]
do
command
done
until 语句
1
2
3
4
until [ 判断语句 ]
do
command
done

3.4 函数

基本格式

1
2
3
4
[function] funcname(){
command
[return n]
}
  • function 关键字可以省略
  • 不用定义参数,而是和命令行参数一样时候用$0 $1 ...的形式来调用
  • 只能返回整数返回值 0~255
    如果没有声明 return 语句,使用最后一条命令的返回值作为返回值

导入包

1
2
3
4
# 实用 . 引入包
. ./file
# 使用 source 关键字引入包
source ./file

引入包相当于把原本包内的多有内容复制到插入点
其中定义的变量和函数都会被定义
同时其中的命令也会全部执行一遍,如果多次引入则会执行多次

4. 调试运行

直接手动在命令行里调试实在是太费劲了

vscode 有很多好用的插件可以支持 shell 的调试和运行

  • Code Runner : 可以支持快速无参数运行测试文件(其实也没啥用,手动运行还能添加参数)
  • Bash debug : 支持调试 Bash(断点,堆栈,变量都支持)

以上两个东西在运行的时候,需要设置TerminalKindintegrated(即用 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<用户名称>: 指定要设定计时器的用户名称

首次使用该命令会进入交互式界面(让选择一款编辑器)
然后给一个文件,该文件中每一行代表一个任务,手动编辑后即保存为周期性任务