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

38 阅读2分钟

**shell基础概念:

终端:获取用户输入,展示运算结果的硬件设备
tty:teletypeWriter的简称,和终端等价,早期指电传印机,在linux中是输入/输出环境
终端模拟器:Mac Terminal、iTerm2等,关联虚拟tty的输入输出软件
Sheel:command interpreter,处理来自终端模拟器的输入,解释执行之后输出结果给终端
Bash:shell的一种具体实现

自定义变量

#变量名=变量值(等号左右两边不能有空格,因为会把空格当成其他命令)

page_size=1

page_num=2

#将命令复制给变量

_ls=ls

#将命令结果赋值给变量

file_list=S(ls -a)

#默认字符串,不会进行+运算

total=page_size*page_num 错误

#声明变量为整型

let total=page_size*page_num

declare -i total=page_size*page_num

#导出环境变量

export total

declare -x total

declare[+/-] 选项 变量

**管道

管道与管道符,作用是将前一个命令的结果传递给后面的命令
语法:cmd1 |cmd2 (将cmd1的输出当作cmd2的输入)
要求:管道右侧的命令必须能接受标准输入才行,比如grep命令,is、mv等不能直接使用,可以使用xargs预处理
注意:管道命令仅仅处理stdout(标准输出),对于stderr会予以忽略(标准输入错误也不会退出)(这是默认形式),可以在脚本前加set-o pipefail设置shell遇到管道错误退出

**判断命令

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

1.整数测试
test $nl -eq $n2    =
test $nl -lt $n2    >
test $nl -gt $n2    <
2.字符串测试
test -z $str_a     字符串为空
test -n $str_a     字符串非空
test $str_a=$str_b      字符串是否相等
3.文件测试
test -e /dmt && echo "exist"    判断文件是否存在
test -f /usr/bin/npm && echo "file exist"  判断文件是否存在并且是一个普通文件
语法:
1.test condition
2.[ conditino ]   (里面必须要有空格符做分割,否则会报错)
3.[[ condition ]]

注意:

1.中括号前后要有空格符

2.[ 和test是命令,只能使用自己支持的标志位,<、>、=只能用来比较字符串

3.中括号内的变量,最好都是用引号括起来

4.[[更丰富,在整型比较中支持<、>、=,在字符串比较中支持=~正则

**分支语句

#语法1:
if condition(判断条件) ;then
   程序段
elif condition ;then
  程序段
esle
  程序段
fi
#语法2:
case $变量 in:
“第一个变量内容”)
   程序段
   ;;
"第一个变量内容”)
  程序段
  ;;
*)
 程序段
  ;;
esac

**循环:

1.while循环
   while condition ; do 程序段; done
2.until循环(条件成立跳出循环)
   until condition ; do 程序段; done
3.for循环
   for var in [word...]; 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";}
例子:
#! /bin/sh

function test() {
  local word="hello world"(在函数内部定义变量时一般会用local限制,表示在当前作用域中生效,避免污染外部的全局作用域。或使用unset将变量撤销)
  echo $word
  return 10

  unset word
}
content='test'

echo“状态码:$?"(返回10)

echo"执行结果: $content"(返回hello world)

注意:

shell自上而下执行,函数必须在使用前定义

函数获取变量和shell script类似,0代表函数名,后续参数通过0代表函数名,后续参数通过1、$2...获取

函数内return仅仅表示函数执行状态,不代表函数执行结果

返回结果一般使用echo、printf,在外面使用$()、"获取结果

如果没有return,函数状态是上一条命令的执行状态,存储在$?中

*模块化

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

source[函数库的路径]

**执行

1.shell脚本一般以.sh结尾,也可以没有,这是一个约定(因为在Linux中以后缀名来做类型的判定的)
     1   #! /bin/bash(第一行需要指定用什么命令解释器来执行)
     1   #! /usr/bin/env bash

2.启动方式
    1  #文件名运行(前提是这个文件名有一个可执行权限的)
    2  ./filename.sh
    3
    4
    5  #解释器运行
    6 bash ./filename.sh
    7
    8
    9 # source 运行
    10 source ./filesome.sh
(前两种会在子进程中执行脚本,第三种会在当前进程中执行脚本)

##执行过程

shell脚本启动——Uer Space去执行

**Uer Space执行过程:

1.字符解析
识别换行符、分号(;)做行的分割
识别命令连接符(||&&管道)做到命令的分割
识别空格、tab符、做命令和参数的分割
(经过字符解析阶段,Space就得到了最基本可执行的命令)
2.shell展开,例如(1..3)解析为 1 2 3
  * (1).大括号展开(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
  *(2).波浪号展开  (Tilde Expansion) ~
#当前用户主目录
~ => $HOME
-/foo => $HOME/foo
#指定用户的主目录
-fred/foo => 用户fred的 $HOME/foo
#当前工作目录
-+/foo => $PWD/foo
#上一个工作目录
~-/foo=> $($OLDPWD-'~-'}/foo
  *(3).参数展开      (Shell Parameter Expansion)
         1).间接参数扩展$(! parameter),其中引用的参数并不是parameter而是parameter的实际的值
         2).参数长度 $(#parameter)
         3).空参数处理
             ${parameter:-word} # 为空替换
             ${parameter:=word} # 为空替换,并将值赋给$parameter变量
             ${parameter:?word} # 为空报错
             ${parameter:+word} # 不为空替换
         4).参数切片
             ${paramenter: offset}
             ${parameter: offset: length}
         5).参数部分删除
             ${parameter%word}# 最小限度从后面截取word
             ${parameter%%word}# 最大限度从后面截取word
             ${parameter#word}# 最小限度从前面截取word
             ${parameter#word}# 最大限度从前面截取word
  *(4).命令替换      (Command Substitution)
    在子进程中执行命令,并用得到的结果替换包裹的内容,形式上有两种:$(...)或'...'
  *(5).数字计算        (Arithmetic Expansion) $((..))
    使用$(())包裹数学运算表达式,得到结果并替换
  *(6).文件名展开   (Filename Expansion)  * ? [..]外壳文件名模式匹配
  当有单词没有被引号包裹,且其中出现了'*','?',and '['字符,则shell会去按照正则匹配的方式查找文件名进行替换,如果没找到则保存不变
3.重定向,将stdin、stdout、stderr的文件描述符进行指向变更
4.执行命令
(1).builtin直接执行
(2).非builtin使用SPATH(环境变量)查找,然后启动子进程执行
5.收集状态并返回

##调试

1.普通log,使用echo、printf

2.使用set命令

3.vscode debug插件

**前端集成

1.node中通过exec、spawn调用shell命令
(exec:启动一个子shell去执行传入的命令,并且将命令的结果存在缓冲区,执行完毕后将缓冲区的结果返回到回调函数当中,有大小限制,默认为200kb
spawn:不会启动子shell进程,spawn会返回一个流对象,直接对流对象进行写入和读取的操作,没有大小限制,适合大数据量的操作)
2.shell脚本中调用node命令
3.借助zx等库进行js、shell script的融合 
——借助shell完成系统操作,文件io、内存、磁盘系统状态查询等
——借助nodejs完成应用层能力,网络io、计算等
shell调用: $'command'