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

1,325 阅读7分钟

Shell 脚本和编程

课程介绍

这节课我们学习shell基础和语法,shell执行过程和原理,shell调试和前端集成。

学习shell 的价值:

  1. Linux 服务器的基本操作和管理
  2. 前端Node.js服务的进程管理、问题排查、资源监控等运维操作
  3. 使用shell 编写TCE、SCM、Docker 脚本,完成服务编译和部署

课程准备

  • 一台安装了linux 系统的物理机或者云主机,可运行shell脚本
  • 本地的vscode 安装Bash Debug 插件, 并升级bash到4.x以上
  • Npm全局安装zx依赖

Shell基础概念

概念

  • Shell是操作系统最外的一层
  • 物理终端=>软件终端tty=>终端模拟器=>shell
  • Shell是Linux内核的一个外层保护工具,也是一个命令行解释器,负责将用户命令解析为操作系统所能理解的指令,实现用户与操作系统的交互。 image.png

发展

3个阶段

  • Ken Thonpson(来自贝尔实验室)在1971年为 UNIX开发了第 个shell,称为 V6 shell
  • Stephen Boume 在贝尔实验室 为 V UNIX 所开发的Bourne shell 即 sh
  • 开源组织GUN为了取代 Boume shell开发的Bourne-Again shell,即Bash

构成

  1. 命令行解释器
  2. 编程语言

image.png

语法和命令

变量

  • shell中的变量类型
  1. 自定义变量
  2. 环境变量
  3. 系统环境变量
类型作用域
自定义变量当前shell
环境变量当前shell及其子shell
系统变量所有shell
声明方式规范
=字符串、整型、浮点型、日期型
export、declare -x
启动加载
  • 父子shell

当父进程在第三方或核心工具时会启动子进程去执行,执行完后交还给父进程,父进程再继续执行下一条命令

自定义变量

#变量名=变量值(等号左右不能有空格)
page_size=1
page_num=2
#将命令复制给变量
_ls=ls
#将命令结果赋值给变量
file_list=$(ls -a)
#默认字符串,不会进行 + 运算

total=page_size*page_num X  (错误)

#声明变量为整型

let total=page_size*page_num 
declare -i total=page_size*page_num 

#导出环境变量
export total
declare -x total

选项含义
-给变量设定类型属性
+取消变量的类型属性
-a将变量声明为数组类型
-i将变量声明为整数型
-x将变量声明为环境变量
-r将变量声明为只读变量
-p显示指定变量的被声明的类型

系统环境变量

  • $0:表示当前执行的脚本或命令的名称
  • $#:表示命令或脚本要处理的参数的个数
  • $*:把所有的参数看成以空格分隔的一个字符串整体(单字符串)返回
  • $?上条命令执行的状态码
  • $PS1命令提示符
  • $HOME用户主文件夹
  • $PATH全局命令的搜索路径

运算符和引用

类型: 算数运算符 逻辑运算符 比较运算符 引号 圆括号 命令连接 后台运行

image.png

管道

Linux 管道使用竖线|连接多个命令,这被称为管道符。Linux 管道的具体语法格式如下: cmd1|cmd2

  • 要求:管道右侧的命令必须能接受标准输入才行,比如grep命令,ls,mv等不能直接使用,可以使用xargs预处理

重定向

重定向可以让我们的程序的标准输出、错误输出的信息重定向文件里,那么么这里还可以将文件的内容代替键盘作为一种标准输入的方式,在C语言的函数为:dup。

输入重定向符号“<” ,“<<”
输出重定向符号“>”,“>>”,“2>”,“&>”

判断命令

shell中提供了test、 [ 、[[ 三种判断符号,可用于:

  • 整数测试
  • 字符串测试
  • 文件测试

语法

  • test condition
  • [condition]
  • [[condition]]

注意

  • 中括号前后要有空格符;
  • [和test是命令,只能使用自己支持的标志位,<、>、=只能用来比较字符串
  • 中括号内的变量,最好都是用引号括起来 -[[更丰富, 在整型比较中支持<、>、=,在字符串比较中支持=~正则

分支语句

shell中分支语句主要是两种:

  • if语句

    if语句经常用在分支不是很多的场景下,if后面的指令,首先会被执行,然后根据指令的返回状态码进入对应的分支。如果状态码为0,也就 是指令执行成功,就进去then的部分;非0则进入其他分支。

    语法:

if condition;then  
  程序段
elif condition;then  
  程序段
  else   
  程序段 
fi

  

  • case语句

当分支较多时可以考虑使用case语句

  case $变量 in:
  "第一个变量内容")
 程序段
 ;;
 "第一个变量内容")
 程序段
 ;;
 *)
 程序段
 ;;
 esac

循环

三种循环:

  • while循环

只要条件成立,则反复循环,不成立即停止

while 条件测试操作 
do  
   命令序列  
done

  • until循环 重复测试某个条件,只要条件不成立则反复循环
until 条件测试操作  
do    
   命令序列  
done
  • for循环 for循环,又有人称之为条件循环,或者for i in ,其实就是for循环的特性,次数和给与的条件是成正比的
for 变量名 in 取值列表  
do                     
   命令序列  
done

函数

将命令序列按格式写在一起,可方便重复使用命令序列 语法

  • funcName(){echo "abc"}
  • function funcName(){echo "abc"}
注意:
  • shell自上而下执行,函数必须在使用前定义
  • 函数获取变量和 shell script类似,0代表函数名,后续参数通过0代表函数名,后续参数通过1、$2...获取
  • 函数内 return仅仅表示函数执行状态, 不代表函数执行结果
  • 返回结果一般使用 echo、 printf,在外面使用$()、'' 获取结果
  • 如果没有 return,函数状态是上一条命令的执行状态,存储在$?中
函数返回值

return表示退出函数并返回一个退出值,脚本中可以用 $ ? 变量显示该值
使用原则:

函数一结束就取返回值,因为$?变量只返回执行的最后一条命令的退出状态码
退出状态码必须是0~255,超出时值将为除以256取余

模块化

原理:在当前shell内执行函数文件

source [函数库的路径]

常用命令

命令使用
grep查找错误日志:grep -n "ERR0R" -A3 -B3 cloudfun. log 统计次数:grep -n "ERROR" -c cloudfun. log
sort指定分隔符后以第三列进行排序:  sort -t" "-k 3
wc统计出现的行数、单词数、字符数wc -1wm
head查看前10行 head -n 10 cloudfun. log
tail等待追加内容: tail -f -n 10 cloudfun. log
cut对数据行的内容进行处理cut -d " " -f 3
find文件和目录查找
xargs参数处理
which查找命令路径

执行过程和原理

执行

shell脚本一般以.sh结尾,也可以没有。

启动方式三种:

  1. 文件名运行

    ./filename.sh

  2. 解释器运行

    bash ./filename.sh

  3. source运行
    source ./filename.sh

执行过程

  1. 字符解析
  2. shell 展开
  3. 重定向
  4. 执行命令
  5. 收集状态并返回

shell展开

  1. 大括号展开(Brase Expansion) {..}

一般由三部分构成:前缀,大括号,后缀 大括号展开是一种可以生成任意字符串的机制。展开大括号的模式采用可选的前缀,后接一系列逗号分隔的字符串或一对大括号之间的序列表达式,后接可选的后缀。前缀与大括号中包含的每个字符串组合,然后将后缀附加到每个结果字符串,从左到右展开。

  1. 波浪号展开(Tilde Expansion) ~

如果一个单词以未加引号的斜杠字符(’ ~ ')开头,则第一个未加引号的斜杠之前的所有字符(如果没有加引号的斜杠,则所有字符)都被视为波浪前缀。如果波浪号前缀中的字符都没有被引用,那么波浪号后面的波浪号前缀中的字符将被视为可能的登录名。如果这个登录名是空字符串,则用shell变量HOME的值替换波浪号。如果没有设置HOME,则替换执行shell的用户的HOME目录。否则,波浪前缀将被替换为与指定登录名关联的主目录。

  1. 参数展开
  • 间接参数扩展${!parameter}
  • 参数长度${#parameter}
  • 空参数处理:parameterword为空替换;{parameter:-word}为空替换;{parameter:=word}为空替换,并赋值给parameter变量;parameter变量;{parameter:?word}为空报错;${parameter:+word}不为空替换。
  • 参数切片
  • 参数部分删除
  1. 命令替换

命令替换允许命令的输出替换命令本身。

  • $(...)
  • ...
  1. 数学计算(Arithmetic Expansion) $((..))

使用$(())包裹数学运算表达式,得到结果并替换。

  1. 文件名展开(Filename Expansion) ?[..]外壳文件名模式匹配 当单词没有被引号包裹,且出现'' '?' '['字符,shell会按照正确的方式查找文件名替换,如果没找到保持不变。

调试和前端集成

调试

  1. 普通log,使用echo,printf
  2. 使用set命令
  3. vscode debug插件

image.png

VSCode配置

插件

  1. shellman:代码提示和自动补全
  2. shellcheck:代码语法校验
  3. shell-format:代码格式化
  4. Bash Debug:支持单步调试

前端集成

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

总结

Shell编程是一种在Linux系统中常用的脚本语言,它可以通过编写一些简单的脚本来完成一些复杂的任务。这节课我们从执行、配置加载、解析过程、语法的顺序去回忆知识脉络,去复习也是很方便的,有多的时间还可以去拓展,了解更多。