Shell编程 | 青训营笔记
课程介绍
- Linux 服务器的基本操作和管理
- 前端 Node.js 服务的进程管理、问题排查、资源监控等运维操作
- 使用 shell 编程 编写 TCE,SCM,Docker 脚本,完成服务编译和部署
课程准备
- 一台安装了 Linux 系统的物理机或者云主机,可运行Shell脚本
- 本地的vscode 安装了 Bash Debug 插件,并升级到 4.x以上
- Npm 全局安装zx依赖
课程内容
- Shell 基础概念
- 命令和语法
- 执行过程和原理
- 调试和前端集成
Shell 基础概念
概念
- 终端
- 获取用户输入,展示运算结果的硬件设备
- tty
- teletypeWriter的简称,和终端等价,早期指电传印机,在linux中是输入\输出环境
- 终端模拟器
- Mac Terminal、iTerm2等,关联虚拟tty的输入输出软件
- Shell
- command interpreter ,处理来着终端模拟器的输入,解释执行之后输出结果给终端
- Bash
- shell的一种具体实现
发展
构成
Shell 既是一种命令语言,又是一种程序设计语言。
Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
语法和命令
变量
自定义变量
#变量名=变量值(等号左右不能要空格)
page_size=1
page_num=2
#将命令复制给变量
_ls=ls
#将命令结果赋值给变量
file_list=$(ls - a)
#默认字符串,不会进行 + 运算
total=page)size+page_num
#声明变量为整型
let taotal=page_size*page_num
declare -i total=page_size*page_num
#导出环境变量
export total
declare -x total
环境变量
#比如
echo $PS1
echo $PATH
配置加载环境
运算符和引用
管道
管道与管道符 | ,作用是将前一个命令的结果传递给后面的命令
语法: cmd1 | cmd2
要求:管道右侧的命令必须能接受标准输入才行,比如 grep 命令,ls、mv等不能直接使用,可以使用 xargs 预处理
注意:管道命令仅仅处理 stdout,对于 stderr 会予以忽略,可以使用 set -o pipefail 设置 shell 遇到管道报错退出
重定向
判断命令
Shell 中提供了 test、[、[[ 三种判断符号,可用于
- 整数测试
- 字符串测试
- 文件测试
语法
- test condition
- [ condition ]
- [[ condition ]]
#整数测试
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"
注意
- 中括号前后要有空格符;
- [ 和 test 是命令,只能使用自己支持的标志位 ,< 、>、= 只能用来比较字符串
- 中括号内的变量,最后都是用引号括起来
- [[ 更丰富、在整型比较中支持 <、>、=、在字符串比较中支持 =~正则
name="hello world"
[ $name == "hello" ]
#报错
scipt.sh: line 5: [ : too many arguments #有太多参数
Exited with error status 2
#原因
#[ $name == "hello" ] 被解析为 [ hello world == "hello" ]
#正确为[ "$name" == "hello" ]
分支语法
循环
- while循环
#while condition ; do 程序段; done
let num=0
while [ $sum -lt 10 ];
do
echo "current idx: $num"
((num++))
done
- until循环
#until condition ; do 程序段; done
let num=0
until [ $num -gt 10 ];
do
echo "current idx: $num"
((num++))
done
- for循环
#for var in [words...]; do 程序段; done
#对列表进行循环
for foo in a b c
do
echo $foo
done
#数值方式循环
for((i=0;i<10;i++))
do
echo $i
done
函数
- 语法一
funcName(){echo "abc";}
- 语法二:
function funcName(){echo "abc";}
printName(){
if [ $# -lt 2 ]; then
echo "illegal parameter."
exit 1
fi
echo "firstname is :$1"
echo "lastname is: $2"
}
printName jacky chen
模块化
模块化的原理是在当前 shell 内执行函数文件,方式:
source [函数库的路径]
常用命令
执行过程和原理
执行
**1.**shell 脚本一般以 .sh 结尾,也可以没有,这是一个约定;第一行需要指定用什么命令解释器来执行
#! /bin/bash
#! /usr/bin/env bash
**2.**启动方式
#文件名运行
./filename.sh
#解释器运行
bash ./filename.sh
#source 运行
source ./filename.sh
执行过程
- 字符解析
- 识别换行符、分号(;)做行的分割
- 识别命令连接符(|| && 管道) 做命令的分割
- 识别空格、tab符、做命令和参数的分割
- shell 展开 ,例如 {1..3} 解析为 1 2 3
- 重定向,将 stdin,stdout,stderr 的文件描述符进行指向变更
- 执行命令
- builtin 执行
- 非 builtin 使用 $PATH;查找,然后启动子进程执行
shell 展开
-
大括号展开(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 -
波浪号展开(Tilde Expansion){...}
#当前用户主目录 ~ => $HOME ~/foo => $HOME/foo #指定用户的主目录 -fred/foo => 用户fred的 $HOME/foo #当前工作目录 ~+/foo => $PWD/foo #上一个工作目录 ~-/foo => ${SOLDPWD-'-'}/foo -
参数展开(Shell Parameter Expansion)
-
命令替换(Command Substiution)
- 在子进程中执行命令,并用得到的结果替换包裹的内容,形式上有两种:$(...) 或
...
#! /bin/bash echo $(wnoimi) foo(){ echi `asdasda` } a=`foo` - 在子进程中执行命令,并用得到的结果替换包裹的内容,形式上有两种:$(...) 或
-
数学计算( Arithmetic Expansion) $((...))
- 使用 $(()) 包裹数学运算表达式,得到结果并替换
#! /bin/bash echo $((1+2)) #3 -
文件名展开(Filename Expansion) * ?[...]外壳文件名模式匹配
- 当有单词没有被引号包裹、且其中出现 '*','and','['字符,则shell会去按照正则匹配的方式查找文件名进行替换,如果没找到则保持不变
#! /bin/bash $ echo D* #输出当前目录下所有以D字母开头的目录,文件
调试和前端集成
调试
- 普通log,使用 echo、print
- 使用 set命令
- vscode debug插件
vscode 配置
- shellman:代码提示和自动补全
- shellcheck:代码语法校验
- shell-format:代码格式化
- Bash Debug:支持单步调试
- 安装vscode 插件
- 编写 launch.json文件
- 升级 bash到4.x版本以上
前端集成
- node中通过 exec、spawn调用 shell命令
- shell脚本中调用 node 命令
- 借助zx库进行 JavaScript、shell script 的融合
- 借助 shell 完成系统操作、文件io、内存、磁盘系统状态查询等
- 借助 node.js 完成应用层能力、网络io、计算等
课程小结
在这次的shell编程中,学习了shell的基础概念,发展,构成,还有shell的语法和命令,shell的执行过程和在前端中如何使用shell