Shell脚本和编程(后半部分)
三种循环
while 循环
while 循环用于在条件成立的情况下重复执行一段代码块
while [ condition ]
do
command1
command2
......
commandN
done
#condition是需要判断的条件,command1到commandN是需要重复执行的命令或者代码块。每次执行完command1到commandN后,都会再次判断condition是否成立,如果成立则继续执行,否则退出循环
until 循环
until 循环与while 循环类似,不同之处在于until 循环在条件不成立的情况下重复执行一段代码块
until [ condition ]
do
command1
command2
......
commandN
done
#condition是需要判断的条件,command1到commandN是需要重复执行的命令或者代码块。每次执行完command1到commandN后,都会再次判断condition是否成立,如果不成立则继续执行,否则退出循环
for 循环
for 循环用于遍历一组数据,并对每个数据执行相同的命令或者代码块
for variable in range
do
command1
command2
......
commandN
done
#variable是用于存储数据的变量名,range是需要遍历的数据范围,可以是数字、字符串、数组等。command1到commandN是需要重复执行的命令或者代码块,每次执行前,variable会被赋值为当前遍历的数据
函数
在 shell 中,函数是一段可以重复使用的代码块,可以在脚本中定义并调用
function_name () {
command1
command2
......
commandN
}
#function_name是函数名,command1到commandN是需要执行的命令或者代码块。定义完函数后,可以在脚本中通过函数名来调用函数
注意:
- 在函数中,使用return语句来返回一个值
- shell 自上而下执行,函数必须在使用前定义
- 函数获取变量和 shell script类似,0代表函数名,后续参数通过1、$2..获取
- 函数内return 仅仅表示函数执行状态,不代表函数执行结果
- 返回结果一般使用echo、printf,在外面使用$()、··获取结果
- 如果没有return,函数状态是上一条命令的执行状态,存储在$? 中
模块化
模块化的原理是在当前shell内执行函数文件,方式:
- source[函数库的路径]
模块化命令
| 命令 | 使用 |
|---|---|
| grep | 查找错误日志:grep -n "ERROR" -A3 -B3 cloudfun.log 统计次数:grep -n “ERROR” -c cloudfun.log |
| sort | 指定分隔符后以第三列进行排序:sort -t “ ” -k 3 |
| wc | 统计出现的行数、单词数、字符数 wc -lwm |
| head | 查看前十行:head -n 10 cloudfun.log |
| tail | 等待追加内容:tail -f -n 10 cloudfun.log |
| cut | 对数据行的内容进行处理 cut -d “ ” -f 3 |
| find | 文件和目录查找 |
| xargs | 参数处理 |
| which | 查找命令路径 |
执行过程与原理
- shell脚本一般以.sh结尾,也可以没有,这是一个约定;第一行需要指定用什么命令解释器来执行
#! /bin/bash
#! /user/bin/env bash
- 启动shell的三种方式
#文件名运行(子进程执行)
./filename.sh
#解释器运行(子进程执行)
bash ./filename.sh
# source运行(当前进程中执行)
source ./filename.sh
执行过程
-
字符解析
- 识别换行符、分号(;)做行的分割
- 识别命令连接符(||&&管道)做命令的分割
- 识别空格、tab符,做命令和参数的分割
-
shell展开,例如{1...3}解析为1 2 3
-
重定向,将stdin、stdout、stderr的文件描述符进行指向变更
-
执行命令
- builtin直接执行
- 非builtin使用$PATH查找,然后启动子进程执行
-
收集状态并返回给脚本
shell展开
Shell 展开是指在执行命令之前,Shell 预处理命令行中的各种特殊字符,将他们替换为实际的值或执行相应的操作
-
大括号展开(Brace Expansion):使用大括号
{}将一组字符串包含在命令行中,Shell 将展开大括号内的所有字符串,并将其作为命令行的一部分。例如:echo file{1..3}.txt将展开为file1.txt file2.txt file3.txt。 -
波浪号展开(Tilde Expansion):使用波浪号
~将用户名或路径名包含在命令行中,Shell 将展开波浪号并将其替换为相应的用户名或路径名。例如:cd ~/Documents将进入当前用户的 Documents 目录。 -
参数展开(Parameter Expansion):使用
$将变量名包含在命令行中,并使用一些特殊符号来修改变量的值或进行字符串操作。例如:${var:-default}表示如果变量$var未定义,则使用默认值default。 -
命令替换(Command Substitution):使用反引号或
$()将一个命令包括起来,Shell 将执行该命令并将其输出作为命令行的一部分。例如:echo "The date is $(date)"将输出当前日期和时间。 -
数学计算(Arithmetic Expansion):使用
$(( ))将一个算术表达式包含在命令行中,Shell 将计算该表达式并将其替换为计算结果。例如:echo $((1+2))将输出3。 -
文件名展开(Filename Expansion):使用通配符
*、?、[]等来匹配文件名或路径名。Shell 将展开通配符并将其替换为匹配的文件名或路径名。例如:ls *.txt将列出当前目录下所有扩展名为.txt的文件。
调试和前端集成
调试的方法
- 普通log,使用echo、printf
- 使用set命令
- vscode debug插件
| set配置 | 作用 | 补充 |
|---|---|---|
| -u | 遇到不存在的变量就会报错,并停止执行 | -o nounset |
| -x | 运行结果前,先输出执行的那一行命令 | -o xtrace |
| -e | 只要发生错误,就终止执行 | -o errexit |
| -o pipefail | 管道符链接的,只要一个子命令失败整个管道命令就失败,脚本就会终止执行 |
#! /bin/bash
#一般在最前面就进行配置
set -uxe -o pipefail
echo "hello world"
VScode插件配置
- shellman:代码提示和自动补全
- shellcheck:代码语法校验
- shell-format:代码格式化
- Bash Debug:支持单步调试
- 安装vscode插件
- 编写launch.json文件
- 升级bash到4.x以上版本
前端集成
- node中通过exec、spawn调用shell命令
- shell脚本中调用node命令
- 借助zx等库进行JavaScript、shell script的融合
学习思考:
补上上次的剩余部分,shell脚本的学习到此为止,但是我感觉这只是基础语法以及一些基础的应用,后续学习中应该会继续深入看一下这部分内容,总之这次的收获还是挺多的。