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

88 阅读4分钟

这是我参与的青训营笔记创作活动的第3

本课程主要涉及:

  • Shell基础概念
  • 命令和语法
  • 执行过程和原理
  • 调试和前端集成

Shell基础概念

概念

1.png

物理终端 => 软件终端tty => 终端虚拟器 => shell

  • tty或者说撞断最开始指的是获取用户输入并输出的物理设备,比如电传打字机

  • 在Linux中是接收用户输入、输出结果的终端仿真软件,比如mac terminal、iterm2等 ,更强输入辅助功能、画面绘制输出的模拟终端器;而tty变成一个虚拟概念,是Linux的一个程序,每个终端模拟器关联一个虚拟tty,和内核打交道。我们可以在终端模拟器中输入tty查看关联到的虚拟tty

  • bash是 shell的一种具体实现,可以理解成实例和类的关系

发展

2.png

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

除了替代v6 shell,sh还有几个优点,把控制流程、循环、变量引入了脚本,提供了一种更具功能性的语言

主流Linux使用的shell,许多都以它为锚点

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

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

构成

3.png

shell不仅提供了与内核和设备交互的方法,还集成了一些今天软件开发中通用的设计模式(比如管道和过滤器),具备控制流程、循环、变量、命名查找的机制即是命令解释器,也是一门编程语言,作为命令解释器,它提供给用户接口,使用丰富的GNU工具集。第三方的或者内置的,比如cd、pwd、exec、test、netstal等等

语法和命令

变量

4.png

5.png

自定义变量

7.png

6.png

系统环境变量

8.png

配置文件加载

9.png

10.png

运算符和引用

11.png

管道

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

  • 语法:cmd1|cdm2

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

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

重定向

12.png

13.png

判断命令

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

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

语法

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

注意

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

# 字符串测试
test -z $str_a
test -n $str_a
test $str_a = $str_b

#文件测试

test -e /dmt $$ echo "exist"
test -f /usr/bin/npm && echo "file exist"

分支语句

14.png

#! bin/bash

level=0
if [ -n "$level" ];then
    if[ "$level" == 0]; then
        prefix=ERROR
    if[ "$level" == 1]; then
        prefix=INFO
    else
        echo "log level not supported"
    fi
fi

echo "[${prefix}]" $message

15.png

#! bin/bash

name=join
case $name in
    "nick")
        echo "hi nick"
     ;;
     "join"
         echo "my name is join"
     ;;
     *)
     
         echo "404"
     ;;
eseac

循环

  • while循环

while condition ;do 程序段; done

  • until循环

until condition ;do 程序段; done

  • for循环

for var in [words...];do 程序段; done

函数

  • 语法一:

funcNmane(){echo"abc;"}

  • 语法二:

function funcNmane(){echo"abc;"}

注意:

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

模块化

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

常用命令

17.png

执行过程和原理

执行

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

#! bin/bash

#! usr/bin/env bash

  1. 启动方式

    #文件名运行
    ./filename.sh

    #解释器运行
    bash ./filename.sh
   
    #source运行
    source ./filename.sh

执行过程

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

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

  3. 执行命令

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

7.收集状态并返回

shell展开

  1. 大括号展开(Brance Expansion) {..}
  2. 波浪号展开(Tilde Expansion) ~
  3. 参数展开(Shell Parameter Expansion)
  • 间接参数展开 $(#parameter)
  • 参数长度 $(!parameter)
  • 空参数处理
    • $(parameter:-word) #为空替换
    • $(parameter:=word) #为空替换,并将值赋给$parameter变量
    • $(parameter:?word) #为空报错
    • $(parameter:+word) #不为空替换
  • 参数切片
    • $(#parameter:offest)
    • $(#parameter:offset:length)
  • 参数部分删除
    • $(parameter%word) #最小限度从后面截取word
    • $(parameter%%word) #最大限度从后面截取word
    • $(parameter#word) #最小限度从前面截取word
    • $(parameter##word) #最大限度从前面截取word
  1. 命令替换(Command Substitution)
  2. 数学计算(Arithmatic Expansion) $((..))
  3. 文件名展开(Filename Expansion) *?[..]外壳文件名模式匹配

调试和前端集成

调试

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

VSCode配置

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

前端集成

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