**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类似,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'