Shell是一种命令行界面,也是一种编程语言, 熟练掌握 Shell 能够大大提升 Unix/Linux环境下的工作效率。
Shell的语法和命令
Shell的自定义变量的作用域是当前Shell,声明方式是=,规范是字符串、整型、浮点型和日期型。环境变量的作用域是当前shell及其子shell,声明方式是export、declare-x。系统环境变量的作用域是所有shell,声明方式是启动加载。
shell的自定义变量书写格式
declare[+/-] 选项 变量
系统环境变量
运算符的符号、作用和用法
管道
管道与管道符|的作用是将前一个命令的结果传递给后面的命令。
语法:
cmd1 | cmd2
要求:
管道右侧的命令必须能接受标准输入才行,比如grep命令,ls、 mv等不能直接使用,可以使用xargs预处理
注意:
管道命令仅仅处理stdout,对于stderr会予以忽略,可以使用 set -o pipefail 设置 shell 遇到管道错误退出 示例如下:
重定向
重定向可以用来修改默认的引用关系
判断命令
shell中提供了test、[、[[ 三种判断符号,可用于:
整数测试、字符串测试、文件测试
- 以test为例:
语法:
- test condition
- [condition]
- [[condition]]
注意:
- 中括号前后要有空格符
- [和test是命令、只能使用自己支持的标志位,<、>、=只能用来比较字符串
- 中括号内的变量,最好都是用引号括起来
- [[更丰富,在整型比较中支持<、>、=,在字符串比较中支持正则表达式
分支语句
语法1:
if condition;then
程序段
elif condition;then
程序段
else
程序段
fi
注:"condition"是判断条件;有多个分支时可使用"elif"(其实就是elseif);"fi"是结尾
示例:
语法2:
case $变量 in:
"第一个变量内容")
程序段
;;
"第一个变量内容")
程序段
;;
*)
程序段
;; easc
注:";;"代表分割;最后的默认分支需要用"*)";"easc"是结尾
示例:
循环
- while循环
while condition;do程序段;done
- until循环
until condition;do程序段;done
- for循环
for var in[words...];do程序段;done
注: until循环与while循环完全相反,表示条件成立时跳出循环;for循环有两种写法:对列表进行循环、数值方式循环
函数
- 语法一:
funcName(){echo"abc";}
- 语法二:
function funcName(){echo"abc";}
注意:
- shell自上而下执行,函数必须在使用前定义
- 函数获取变量和shell script类似,1、$2...获取
- 函数内 return 仅仅表示函数执行状念 不代表函数执行结果
- 返回结果一般使用echo、printf,在外面使用$()、`` 获取结果
- 如果没有return,函数状态是上一条命令的执行状态,存储在$?中
模块化
模块化的原理是在当前shell内执行函数文件,方式:
source[函数库的路径]
示例:
常用命令
Shell执行过程和原理
执行
1、shell脚本一般以.sh结尾,也可以没有,这是一个约定;第一行需要指定用什么命令解释器来执行
2、启动方式
注: 文件名运行的前提是此文件名有可执行权限;文件名运行和解释器运行会在子进程中执行脚本,source运行会在当前进程中执行脚本
执行过程
1. 字符解析
- 识别换行符、分号(;)做行的分割
- 识别命令连接符(|| && 管道)做命令的分割
- 识别空格、tab符,做命令和参数的分割
2. shell 展开,例如{1..3}解析为 1 2 3
3.重定向,将stdin、sidout、stderr的文件描述符进行指向变更
4.执行命令
- builtin 直接执行
- 非builtin使用$PATH查找,然后启动子进程执行
5.收集状态并返回
Shell展开
1. 大括号展开(Brace Expansion){...}
一般由三部分构成,前缀、一对大括号、后缀,大括号内可以是逗号分割的字符串序列,也可以是序列表达式{x..y[..incr]}
2. 波浪号展开(Tilde Expansion) ~
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
- ${parameter6%word}#最大限度从后面截取word
- ${parameter#word}#最小限度从前面截取word
- ${parameter##word}#最大限度从前面截取word
4. 命令替换(Command Substitution)
在子进程中执行命令 并用得到的结果替换包裹的内容, 形式上有两种:$(...)或 '...'(实际上'应该是`的,但是打不出来)
5. 数学计算(Arithmetic Expansion) $((..))
使用$(())包裹数学运算表达式,得到结果并替换
6. 文件名展开(Filename Expansion) * ?[..]外壳文件名模式匹配
当有单词没有被引号包裹,且其中出现了‘*’,‘?’,and‘[’字符,则shell会去按照正则匹配的方式查找文件名进行替换,如果没找到则保持不变。
调试
- 普通log,使用echo、printf
- 使用set命令
- vscode debug插件
注: 一般在shell最开头使用set进行以下配置
vscode配置
- shellman:代码提示和自动补全
- shellcheck:代码语法校验
- shell-format:代码格式化
- Bash Debug:支持单步调试
注: 使用Bash Debug需要安装vscode插件、编写launch.json文件、升级bash到4.x以上版本,否则此插件无效
前端集成
- node中通过exec、spawn调用shell命令
- shell脚本中调用node命令
- 借助zx等库进行JavaScript、shell script的融合
(借助shell完成系统操作,文件io、内存、磁盘系统状态查询等;借助nodejs完成应用能力,网络io、计算等)