笔记标题|青训营笔记 [Shell 脚本和编程|青训笔记]

115 阅读3分钟

Shell 脚本和编程

学习shell的价值:

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

课程准备

  1. 一台安装了linux系统的物理机或者云主机,可运行shell脚本
  2. 本地的vscode安装Bash Debug插件,并升级bash到4.x以上
  3. Npm全局安装zx依赖

Shell基础概念

概念

1681720781314.png

发展

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

1681720858530.png

构成

Unix shell既是一种命令解释器,也是一种编程语言。作为一个命令解释器,shell为丰富的GNU实用程序集提供了用户界面。这个

1681721248875.png

变量

1681721340783.png

自定义变量只用在父进程才可以使用 环境变量可以在子进程和父进程中使用

自定义变量


#!/bin/bash

#变量名=变量值(等号左右不能有空格)
page_size=1
page_num=2

#将命令复制给变量
_ls=ls

# 将命令结果赋值给变量
file_list=$(ls -a)

#默认字符串,不会进行 + 运算
total=page_size*page_num

declare -i total=page_size*page_num

#导出环境变量
export total

dexlare -x total

1681721923937.png

系统环境变量

1681721941395.png

配置文件加载

1681721962353.png

 启动脚本 source ~/.bashrc

运算符和引用

1681721972020.png

管道

管道与管道符|,作用是将一个命令的结果传递给后面的命令 语法:cmd1|cmd2 要求:管道右侧的命令必须能接受标准输入行,比如grep命令,IS、mv等不能直接使用,可以使用xargs预处理

#!/bin/bash

cat platform.access.log | grep ERROR 

netstat -an | grep ESTABLISHED | wc -l

find . -maxdepth 1 -name "-*.sh" | xargs ls -l

重定向

1681721998682.png

输出重定向符号

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

输入重定向符号

<
<<

判断命令

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

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

语法:

  • test condition
  • [condition]
  • [[condition]]
#!/bin/bash

#整数测试
test $nl -eq(等于) $n2  
test $nl -lt(小于) $n2  
test $nl -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" 

注意

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

1681724975383.png

分支语句

1681725068262.png

1681725078431.png

循环

while循环

  • while condition ; do 程序段; done
#!/bin/bash

let num=0

while [$num -lt 10 ]
do
   echo "current idx:$num"
    ((num++))
done

until循环

  • until condition ; do 程序段; done
#!/bin/bash

let num=0

until [$num-gt 10];
do
   echo "current idx: $num"
   ((num++))
done

for循环

  • for var in [words...]; do 程序段; done
#/bin/bash

#对列表进行循环
 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";}

#!/bin/bash
printName(){

   if[ $#-lt 2]; then
      echo "illegal parameter."
      exit 1
     fi
      echo "firstname is:$1"
      echo "lastname is:$2"
}
printName jacky chen
#!/bin/sh


function test(){
  local word="hello world"
  echo $word
  return 10
  
  unset word
}
content='test'
echo"状态码: $?"
echo"执行结果:$content"

注意:

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

模块化

模块化的原理是在当前shell内执行函数文件,方式: source [函数库的路径]

1681726458441.png

常用的命令

1681726537991.png

行过程和原理

执行

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

#/bin/bash

#/usr/bin/env bash


    启动方式
#文件名运行
./filename.sh


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

source运行
source ./filename.sh

执行过程

1681726915980.png

1. 字符解析

  • 识别换行符、分号(;)做行的分割
  • 识别命令连接符(|| && 管道)做命令的分割
  • 识别空格、tab符,做命令和参数的分割

2. shell展开,列如{1..3} 解析为1 2 3

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

4. 执行命令

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

5. 收集状态并返回

shell展开

1681729626171.png

大括号展开(Brace Expansion){...} 一般由三部分构成,前缀,一对大括号、后缀,大括号可以是逗号分隔的字符串序列,也可以是序列表达式{x..y[..incr]}

1681727582068.png

波浪号展开(Tilde Expansion)

1681727676037.png

参数展开(Shell Parameter Expansion) ${}

l.间接参数扩展${!parameter},其中引用的参数并不是parameter而是parameter的实际的值

1681727925723.png

2.参数长度${#parameter)

1681727951645.png

3.空参数处理

 ${parameter:-word}#为空替换
 ${parameter:=word}#为空替换,并将值赋给$parameter变量
 ${parameter:?word}#为空报错
 ${parameter:+word#不为空替换

1681727986084.png

4.参数切片

${parameter:offset}
${parameter:offset:length}

5.参数部分删除

 ${parameter%word}#最小限度从后面截取word
 ${parameter%%word}#最大限度从后面截取word
 ${parameter#word}#最小限度从前面截取word
 ${parameter##word}#最大限度从前面截取word

1681728082915.png

命令替换(Command Substitution)

在子进程中执行命令,并用得到的结果替换包裹的内容,形式上有两种:$(..)或...

1681728439493.png

数学计算(Arithmetic Expansion)$((..))

使用$(())包裹数学运算表达式,得到结果并替换

#!/bin/bash

echo$((1+2))#3

文件名展开(Filename Expansion) * ? [..]外壳文件名模式匹配

当有单词没有被引号包裹,且某中出现了'*','?',and '['字符,则shell会去按照正则匹配的方式查找文件名进行替换,如果没找到则保持不变。

!#/bin/bash

 $ echo D*

#输出当前目录下所有以D字母开头的目录、文件

调试和前端集成

1.普通log,使用echo、printf

#!/bin/sh

a=1
d=(1 2 3 4 5)
echo $a
echo $(d[3]}
echo $(d[@]}
#
输出
#1
#4
#
12345

2.使用set命令

1681729204624.png

1681729255243.png

3.vscode debug插件

VSCode配置

  1. shellman:代码提示和自动补全
  2. shellcheck:代码语法校验
  3. shell-format:代码格式化
  4. Bash Debug:支持单步调试
  • 安装vscode插件
  • 编写launch.json文件
  • 升级bash到4.x以上版本

1681729431292.png

前端集成

1681729564658.png

课程小结

1681729593096.png