这是我参与的青训营笔记创作活动的第3天
本课程主要涉及:
- Shell基础概念
- 命令和语法
- 执行过程和原理
- 调试和前端集成
Shell基础概念
概念
物理终端 => 软件终端tty => 终端虚拟器 => shell
-
tty或者说撞断最开始指的是获取用户输入并输出的物理设备,比如电传打字机
-
在Linux中是接收用户输入、输出结果的终端仿真软件,比如mac terminal、iterm2等 ,更强输入辅助功能、画面绘制输出的模拟终端器;而tty变成一个虚拟概念,是Linux的一个程序,每个终端模拟器关联一个虚拟tty,和内核打交道。我们可以在终端模拟器中输入tty查看关联到的虚拟tty
-
bash是 shell的一种具体实现,可以理解成实例和类的关系
发展
- 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),一些实用环境变量,命令自动补全等
构成
shell不仅提供了与内核和设备交互的方法,还集成了一些今天软件开发中通用的设计模式(比如管道和过滤器),具备控制流程、循环、变量、命名查找的机制即是命令解释器,也是一门编程语言,作为命令解释器,它提供给用户接口,使用丰富的GNU工具集。第三方的或者内置的,比如cd、pwd、exec、test、netstal等等
语法和命令
变量
自定义变量
系统环境变量
配置文件加载
运算符和引用
管道
管道与管道符|,作用是将一个命令的结果传递给后面的命令
-
语法:cmd1|cdm2
-
要求:管道右侧的命令必须能接受标准输入才行,比如gerp命令,ls、mv等不能直接使用,可以使用xargs预处理
-
注意:管道命令不仅仅处理stdout,对于是他的人人会予以忽略。可以使用set-o pipefail设置shell遇到管道错误退出
重定向
判断命令
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"
分支语句
#! 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
#! 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类似,1、$2...获取
- 函数内return仅仅表示函数的执行状态,不代表函数执行结果
- 返回结果一般使用echo、printf、在外面使用$()、``获取结果
- 如果没有return,函数状态是上一条命令的执行状态,存储在$?中
模块化
模块化的原理是在当前shell内执行函数文件,方式:
常用命令
执行过程和原理
执行
- shell脚本一般以.sh结尾,也可以没有,这是一个约定;第一行需要指定用什么命令解释器来执行
#! bin/bash
#! usr/bin/env bash
- 启动方式
#文件名运行
./filename.sh
#解释器运行
bash ./filename.sh
#source运行
source ./filename.sh
执行过程
- 字符解析
- 识别换行符、 分号(;)做行的分割
- 识别命令连接符(||&&管道)做命令的分割
- 识别空格、tab符,做命令和参数的分割
-
shell展开,例如{..3} 解析为123
-
重定向,将stdin、 stdout. stderr的文件描述符进行指向变更
-
执行命令
- builtin直接执行.
- 非builtin使用$PATH查找,然后启动子进程执行
7.收集状态并返回
shell展开
- 大括号展开(Brance Expansion) {..}
- 波浪号展开(Tilde Expansion) ~
- 参数展开(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
- 命令替换(Command Substitution)
- 数学计算(Arithmatic Expansion) $((..))
- 文件名展开(Filename Expansion) *?[..]外壳文件名模式匹配
调试和前端集成
调试
- 普通log,使用echo、printf
- 使用set命令
- vscode debug插件
VSCode配置
- shellman:代码提示和自动补全
- shellcheck:代码语法校验
- shell-format:代码格式化
- Bash Debug:支持单步调试
前端集成
- node中通过exec、spawn调用shell命令
- shell脚本中调用node命令
- 借助zx等库进行JavaScript、shell script的融合