Shell脚本和编程 | 青训营笔记

211 阅读4分钟

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[函数库的路径]

image.png

模块化命令

命令使用
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查找命令路径

执行过程与原理

  1. shell脚本一般以.sh结尾,也可以没有,这是一个约定;第一行需要指定用什么命令解释器来执行
#! /bin/bash
#! /user/bin/env bash
  1. 启动shell的三种方式
#文件名运行(子进程执行)
./filename.sh


#解释器运行(子进程执行)
bash ./filename.sh


# source运行(当前进程中执行)
source ./filename.sh

执行过程

  1. 字符解析

    • 识别换行符、分号(;)做行的分割
    • 识别命令连接符(||&&管道)做命令的分割
    • 识别空格、tab符,做命令和参数的分割
  2. shell展开,例如{1...3}解析为1 2 3

  3. 重定向,将stdin、stdout、stderr的文件描述符进行指向变更

  4. 执行命令

    • builtin直接执行
    • 非builtin使用$PATH查找,然后启动子进程执行
  5. 收集状态并返回给脚本

shell展开

Shell 展开是指在执行命令之前,Shell 预处理命令行中的各种特殊字符,将他们替换为实际的值或执行相应的操作

  1. 大括号展开(Brace Expansion):使用大括号 {} 将一组字符串包含在命令行中,Shell 将展开大括号内的所有字符串,并将其作为命令行的一部分。例如:echo file{1..3}.txt 将展开为 file1.txt file2.txt file3.txt

  2. 波浪号展开(Tilde Expansion):使用波浪号 ~ 将用户名或路径名包含在命令行中,Shell 将展开波浪号并将其替换为相应的用户名或路径名。例如:cd ~/Documents 将进入当前用户的 Documents 目录。

  3. 参数展开(Parameter Expansion):使用 $ 将变量名包含在命令行中,并使用一些特殊符号来修改变量的值或进行字符串操作。例如:${var:-default} 表示如果变量 $var 未定义,则使用默认值 default

  4. 命令替换(Command Substitution):使用反引号或 $() 将一个命令包括起来,Shell 将执行该命令并将其输出作为命令行的一部分。例如:echo "The date is $(date)" 将输出当前日期和时间。

  5. 数学计算(Arithmetic Expansion):使用 $(( )) 将一个算术表达式包含在命令行中,Shell 将计算该表达式并将其替换为计算结果。例如:echo $((1+2)) 将输出 3

  6. 文件名展开(Filename Expansion):使用通配符 *?[] 等来匹配文件名或路径名。Shell 将展开通配符并将其替换为匹配的文件名或路径名。例如:ls *.txt 将列出当前目录下所有扩展名为 .txt 的文件。

调试和前端集成

调试的方法

  1. 普通log,使用echo、printf
  2. 使用set命令
  3. vscode debug插件
set配置作用补充
-u遇到不存在的变量就会报错,并停止执行-o nounset
-x运行结果前,先输出执行的那一行命令-o xtrace
-e只要发生错误,就终止执行-o errexit
-o pipefail管道符链接的,只要一个子命令失败整个管道命令就失败,脚本就会终止执行
#! /bin/bash

#一般在最前面就进行配置
set -uxe -o pipefail

echo "hello world"

VScode插件配置

  1. shellman:代码提示和自动补全
  2. shellcheck:代码语法校验
  3. shell-format:代码格式化
  4. Bash Debug:支持单步调试
    • 安装vscode插件
    • 编写launch.json文件
    • 升级bash到4.x以上版本

前端集成

  1. node中通过exec、spawn调用shell命令
  2. shell脚本中调用node命令
  3. 借助zx等库进行JavaScript、shell script的融合

学习思考:

补上上次的剩余部分,shell脚本的学习到此为止,但是我感觉这只是基础语法以及一些基础的应用,后续学习中应该会继续深入看一下这部分内容,总之这次的收获还是挺多的。