shell脚本及编程 | 青训营笔记

140 阅读6分钟

shell脚本与编程

01.shell基本概念

01_基础概念

image-20230417160055932.png 物理终端 => 软件终端tty => 终端模拟器 => shell

(终端与tty是一个等价的概念)

  • 最初, tty与终端最开始指的就是获取用户输入并输出的物理设备,如:电传打字机, 现在在Linux中是接收用户输入 输出结果的终端仿真软件
  • 终端模拟器关联着虚拟tty,可以在终端模拟器中输入tty查看关联到的tty
  • bash是shell的一种具体实现(可以理解为类(shell) 与 实例(bash) 的关系)

01_发展

image-20230417160410183.png

bash是sh的超集, 可以直接执行大部分的sh脚本

同时 Bash在兼容Bourne shell脚本编程的同时, 集成了ksh 与 csh的功能,包括命令历史、命令行编辑、目录堆栈(pushd 和 popd),一些实用环境变量、命令自动补全等

01_构成

image-20230417193958794.png

shell不仅提供了与内核和设备交互的方法,还集成了一些如今软件开发中通用的设计模式(如管道和过滤器),具备控制流程、循环、变量、命令查找的机制

即是命令解释器,也是一门编程语言,作为命令解释器,他提供给用户接口,使用丰富的GUN工具,第三方的或者内置的,比如cd、pwd、test、exec、netstat等

02.命令和语法

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

可以看下图

image-20230417194610840.png

02_自定义变量

image-20230417194720900.png

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

02_系统环境变量

变量名含义常见操作
$o当前shell名称 / 脚本名称11、2等可以获取到传入参数
$#传入脚本的参数数量if [$#-gt1]
$*传入脚本的所有参数
$?上条命令执行的状态码if[$?-eqo];
$PS1命令提示符export PS1-"\u@\h\w>"
$HOME用户主文件夹cd~
$PATH全局命令的搜索路径PATH=$PATH:[新增路径]

02_配置文件加载

image-20230417195657307.png

  • login shell:取得bash需要完整的登录流程
  • non-login bash:ssh远程登录一台主机不需要登录的bash

02_运算符及其引用

image-20230417200046632.png

02_管道

管道与管道符 | ,作用是将前一个命令的结果传递给后面的命令

语法: cmd1 | cmd2

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

注意: 管道命令仅仅处理stdout,对于stderr会予以忽略,可以使用set -o pipefail设置shell遇到管道错误退出

#!/bin/bash
cat platform.access,log | grep ERROR
netstat -an | grep ESTABLISHED | wc -1
find . -maxdepth 1 -name "*.sh" | xargs ls -1

如果需要互通,如一个命令的返回传递给第二个命令,就需要用到管道了,

管道的本质就是将多个程序进行了一个连接,和信号一样,也是进程通信的方式之一

02_重定向

image-20230417200914393.png

每个shell命令在执行时都会打开三个文件描述符,文件描述符0、1、2分别对应stdin、stdout、stderr,这三个文件描述符默认指向终端输入、终端输出,那么当命令需要获取输入的时候,它会去读取fd0,当要输出的时候,它会像fd1、fd2写入,改变这些描述指向的行为叫做重定向

02_判断命令

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

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

语法:

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

注意:

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

02_分支语句

image-20230417201733319.png

02_循环

image-20230417201852542.png

02_函数

语法一:

function(){ echo "abc" ;}

语法二:

function funcName(){ echo "abc"; }

注意:

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

image-20230417202510434.png

02_模块化

模块化的原理是在当前shell内执行函数文件,方式:

source [函数库的路径]

image-20230417202510434.png

02_常用命令

image-20230417202833788.png

03.执行过程和原理

03_执行

1.shell脚本一般以.sh结尾,也可以没有,这是一个约定;第一行需要指定用声什么命令解释器来执行

#! /bin/bash
#! /usr/bin/env/ bash

2.启动方式

# 文件名运行
./filename.sh
​
# 解释器运行
bash ./filename.sh
​
# source 运行
source ./filename.sh

03_执行过程

1.字符解析

  • 识别换行符、分号(;)做行的分割
  • 识别命令连接符(|| && 管道)做命令的分割
  • 识别空格、tab符,做命令和参数的分割

2.shell 展开,例如 {1, 3} 解析为 1 2 3

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

4.执行命令

  • builtin 直接执行
  • 非builtin使用$PATH查找,然后启动子进程执行

5.收集状态并返回

image-20230417204604921.png

03_shell展开

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

一般由三部分构成,前缀、一对大括号、后缀,大括号内可以是序列表达式{x..y[..incr]}

# 字符串序列
a{b,c,d}e => abe ace ade
​
#表达式序列,(数字可以使用incr调整增量,字符不行)
{1..5} => 1 2 3 4 5
{1..5..2} => 1 3 5
{a..e} => a b c d e

2.波浪号(Tide Expansion)~

# 当前用户主目录
- => $HOME
~/foo => $HOME/foo
​
#指定用户的主目录
~fred/foo => 用户fred的$HOME/foo
​
#当前工作目录
~-+/foo => $PWD/foo
​
#上一个工作目录
~-/foo => ${$OLDPWD- '~-'}/foo

3.参数展开(Shell Parameter Expansion)${}

1.间接参数扩展${!parameter}, 其中引用的参数并不是parameter而是parameter的实际的值

2.参数长度${#parameter}

3.空参数长度

${parameter:-word} # 为空替换

{parameter:=word} # 为空替换,并将值赋给parameter变量

${parameter:?word} # 为空报错

${parameter:+word} # 不为空替换

4.参数切片

${parameter:offset}

${parameter:offset:length}

5.参数部分删除

${parameter%word} # 最小限度从后面截取word

${parameter%%word} # 最大限度从后面截取word

${parameter#word} # 最小限度从前面截取word

${parameter##word} # 最大限度从前面截取word、

4.命令替换

在子进程中执行命令,并用得到的结果替换包裹的内容,形式上有两种:${...} 或 ...

#!/bin/bashecho ${whoimi}foo(){
    echo "asdasd"
}
​
a=`foo`

5.数学计算(Arithmetic Expansion)$((...))

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

#! /bin/bashecho $((1+2)) # 3

6.文件名展开(Filename Expansion)*?[...] 外壳文件名模式匹配

当有单词没有被引号包裹,且其中出现了 '*', '?' , and , '[' 字符,则shell会去按照正则匹配的方式查找文件名进行替换,如果没找到则保持不变。

#!/bin/bash$ echo D*#输出当前目录下所有以D字母开头的目录、文件

04.调试和前端集成

04_调试

1.普通log,使用echo、printf

2.使用set命令

3.vscode debug插件

set配置作用补充
-u遇到不存在的变量就会报错,并停止执行-o nounset
-x运行结果之前,先输出执行的哪一行命令-o xtrace
-e只要发生错误,就终止执行-o errexit
-o pipefail管道链接的,只要一个子命令失败,整个管道命令就失败,脚本就会终止执行。

04_VSCode配置

1.shellman:代码提示的自动补全

2.shellcheck:代码语法校验

3.shell-format:代码格式化

3.Bash Debug:支持单步调试

  • 安装vcode插件
  • 编写launch.json文件
  • 升级bash到4x以上版本

image-20230417211429091.png

04_前端集成

1.node中通过exec、sqawn调用shell命令

2.shell脚本中调用node命令

3.借助zx等库进行javascript、shell script的融合

  • 借助shell完成系统操作,文件io、内存、磁盘系统状态查
  • 借助nodejs完成应用层能力,网络io、计算等

image-20230417211736026.png

image-20230417211747129.png