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

99 阅读4分钟

Shell 脚本和编程

笔者:YDSUPER

课程地址:点我前往

零、课程介绍

  • Linux服务器的基本操作和管理
  • 前端 Node.js 服务的进程管理、问题排查、资源监控等运维操作
  • 使用 shell 编写 TCE、SCM、Docker 脚本,完成服务编泽和部署

一、Shell 基础概念

概念

  • 终端 获取用户输入、展示运输结果的硬件设备

  • tty teletypeWriter的简称,和终端等价,早期指电传打印机,在linux中是 输入/输出 环境

  • 终端模拟器 Mac Terminal、iTerm2等,关联虚拟tty的输入输出软件

  • Shell

    command interpreter,处理来自终端模拟器的输入,解释执行之后输出结果给终端

  • Bash

    shell的一种具体实现

发展

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

image.png

构成

image-16833627967202.png

二、命令和语法

变量

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

image-16833639796754.png

自定义变量

image-20230506171149717.png

declare [+/-] 选项 变量
image-20230506170927207.png

系统环境变量

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

配置文件加载

source ~/.bashrc  #执行脚本 生效

image-16833664988056.png

运算符和引用

类型符号作用用法
算数运算符+ - * / % | &常规运算
逻辑运算符|| && !
比较运算符== != < >
引号双引号 “”部分引用,仅仅$、\保留作用foo="$ {a} 123"
单引号 ‘’完全引用,原样输出foo='foo$a'
反引号 ``执行命令foo= `1s - a`
圆括号(())算数运算foo=$((1+2))
()执行命令$(1s -a)
命令连接||cmd1执行完且返回码非0,则继续执行 cmd2cmd1 || cmd2
&&cmd1执行完且返回码为0,则继续执行 cmd2cmd1 && cmd2
;cmd1、cmd2串行执行cmd1 ; cmd2
后台运行&让命令在后台运行,可与nohup一起使用cmd &

管道

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

  • 语法:cmd1 | cmd2

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

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

image-20230506175652983.png

重定向

  • 输出重定向符号

    >:覆盖写入文件

    >>:追加写入文件 2>:错误输出写入文件 &>:正确和错误输出统一写入到文件中

  • 输入重定向符号

    <

    <<

image-16833671576018.png image-168336716757810.png

判断命令

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

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

语法:

  • test condition
  • [ condition ]
  • [[ condition ]]
# 整数测试
test $n1 -eq $n2
test $n1 -lt $n2
test $n1 -gt $n2
# -eg/-lg/-gt 分别代表:等于/小于/大于

# 字符串测试
test -z $str_a  #判断是否为空
test -n $str_a  #判断是否非空
test $str_a = $str_b  #判断是否相对

# 文件测试
test -e /dmt && echo ""  #判断文件是否存在 并在存在时输出 "exist
test -f /user/bin/npm && echo "file exist"  #判断文件是否存在且是一个普通文件

注意:

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

name="hello world"

[ $name == "hello" ] ❌  会被解析成:[ hello world == "hello" ] #字符串没带上引号

[ "$name" == "hello" ] ✅

分支语句

语法1:
if condition; then
  程序段
elif condition; then
  程序段
else
  程序段
fi
语法2:
case $变量 in:
  "第一个变量内容")
    程序段
    ;;
  "第二个变量内容")
    程序段
    ;;
   *)
   程序段
   ;;
esac

循环

  • while 循环

    while condition ; do 程序段; done
    
  • until 循环

    until condition ; do 程序段; 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 "xxx"; }

# 语法二
funciton funcName() { echo "xxx"; }

# 调用
funcName aaa bbb  
# 1.空格间隔传参
# 2.内部通过 $1 $2... 接收参数

# 扩展
函数内使用 local 定义变量,避免全局污染
也可以最后使用 unset 变量 将变量撤销掉

注意:

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

模块化

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

source [函数库的路径]

image-20230509162154707.png

常用命令

命令使用
grep查找错误日志:grep -n "ERROR" -A3 -B3 cloudfun.log
统计次数:grep -n "ERROR" -c cloundfun.log
sort指定分隔符后以第三列进行排序:sort -t " " -k 3
wc统计出现的行数、单词数、字符数:wc -lwm
head查看前十行:head -n 10 cloudfun.log
tail等待追加内容:tail -f -n 10 cloudfun.log
cut对数据行的内容进行处理:cut -d " " -f 3
find文件和目录查找
xargs参数处理
which查找命令路径

三、执行过程和原理

执行

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

    #! /bin/bash
    
    #! /user/bin/env bash
    
  • 启动方式

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

执行过程

  1. 字符解析
  2. shell 展开,例如 {1..3} 解析为:1 2 3
  3. 重定向,将stdin、stdout、stderr的文件描述符进行指向变更
  4. 执行命令
    • builtin 直接指向
    • 非 builtin 使用 $PATH 查找,然后启动子进程执行
  5. 收集状态并返回

image-168378664053116.png

shell展开

  1. 大括号展开 {...}
  2. 波浪号展开 ~
  3. 参数展开
  4. 命令替换
  5. 数学计算 $((..))
  6. 文件名展开 *?[..] 外壳文件名模式匹配

四、调式和前端集成

调试

  1. 普通log,使用echo、printf
  2. 使用 set 命令
  3. vscode debug插件
set 配置作用补充
-u遇到不存在的变量就会报错,并停止执行-o nounset
-x运行结果之前,先输出执行的那一行命令-o xtrace
-e只要发生错误,就终止执行-o errexit
-o pipefail管道符链接的,只要一个子命令失败,整个管道命令就失败,脚本就会终止执行

VSCode 配置

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

  2. shellcheck:代码语法校验

  3. shell-format:代码格式化

  4. Bash Debbug:支持单步调试

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

    image-168378605195014.png

前端集成

  1. node中通过exec、spawn调用 shell 命令
  2. shell 脚本中调用 node 命令
  3. 借助 zx 等库进行 javascript、shell script 的融合
    • 借助 shell 完成系统操作,文件io、内存、磁盘系统状态查询
    • 借助 nodejs 完成应用层能力,网络io、计算等

总结

image-168377702807512.png