Shell脚本和编程
学习shell的价值
在工作当中,或多或少会遇到需要使用shell的地方,所以学习shell是十分有必要的,shell可以用在一下三点
- Linux服务器的基本操作和管理
- 前端Node.js服务的进程管理、问题排查、资源监控等运维操作
- 使用shell编写TCE、SC、Docker脚本,完成服务编译和部署
shell基础
shell首先是一个命令行解释器,其次它是一门编程语言.shell作为解释器可以解释执行脚本和命令,同时也提供了很多的内置命令,例如图中的"[","echo"等.shell作为一门编程语言,也提供了定义变量和使用变量的能力
作为编程语言的语法和命令
变量
自定义变量用"="声明,默认声明变量都是字符串型,整形、浮点型和日期型需要手动声明,作用域在当前shell
环境变量用"export"、"declare -x"声明,作用域在当前shell及其子shell
系统环境变量是在shell启动时加载进来,作用域在所有shell
父子shell
当父进程执行第三方或者核心工具时会启动子进程执行,执行完后交还给父进程,父进程继续执行下一条命令.在这过程中自定义变量只有在父进程中可以用到,环境变量和系统环境变量在父进程和子进程中都可以用到
自定义变量
# 变量名=变量值
page_size=1
page_num=2
# 将命令复制给变量
_ls=ls
# 将命令结果赋值给变量
file_list=$(ls -a)
# 声明变量为整形
let total=page_size*page_num
declare -i total=page_size*page_num
# 导出环境变量
export total
declare -x total
其中"="两边不能有空格,否则shell会当作额外命令.由于默认声明变量都是字符串,所以不会进行算数运算,声明变量为整形需要用到
let或者declare -i
declare基本选项
declare -给变量设定类型属性declare +取消变量的类型属性declare -a将变量声明为数组类型declare -i将变量声明为整数型declare -x将变量声明为环境变量declare- r将变量声明为只读变量declare -p显示指定变量的被声明的类型
系统环境变量
环境变量可以通过
vim ~/bashrc进行配置,配置完成后运行source ~/bashrc
运算符和引用
管道
管道与管道符|,作用是将前一个命令的结果传递给后面的命令传递给后面的命令
语法cmd1|cmd2
要求: 管道右侧的命令必须能接受标准输入才行,比如grep命令,ls、mv等不能直接使用,可以使用xargs预处理.xargs工作原理是将标准输入转化成参数列表的形式.
注意: 管道命令仅仅处理标准输出,对于标准错误输出会予以忽略,可以使用set -o pipefall设置shell遇到的管道错误退出
cat platform.access.log | grep ERROR 使用cat查看platform.access.log内容并将内容作为grep命令的输入
netstat -an | grep ESTABLISHED | wc -l使用netstat查看网络连接状态传递给grep,grep筛选后的结果再传递给wc命令做统计
重定向
fd0指向终端输入,fd1指向终端输出,fd2指向终端输出,而重定向的作用就是修改fd1,fd2,fd3的指向,如下图所示
通过重定向,fd0指向了~./bashrc,fd1和fd2指向了tempfile
输出重定向符号
>: 覆盖写入文件>>: 追加写入文件2>: 错误输出写入文件&>: 正确和错误输出统一写入到文件中
输入重定向符号
<<<
判断命令
shell中提供了test、[、[[三种判断符号,可用于:
- 整数测试
- 字符串测试
- 文件测试
语法:
test condition[condition][[condition]]
整数测试
test $n1 -eq $n2判断n1是否等于n2test $n1 -lt $n2判断n1是否小于n2test $n1 -gt $n2判断n1是否大于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是命令,只能使用自己支持的标志位,<、>、=只能用来比较字符串
- 中括号内的变量,最好都是用引号括起来
- [[更丰富,在整形比较中支持<、>、=.在字符串比较中支持=~正则
分支语句
语法一:
if condition;then
程序段
elif condition;then
程序段
else
程序段
fi
语法二:
case $变量 in:
"第一个变量内容")
程序段
;;
"第二个变量内容")
程序段
;;
*)
程序段
;;
esac
其中if语句与我们熟悉的C,C++语言不同,if语句第一不需要小括号,其次if判断之后需要加上;之后是then,与python相同的是elif的写法,最后结束if语句是fi,正好是if倒过来的写法
case语句变量内容后要加上),程序段结束后要加上;;,最后case语句结束后要加上esac
循环
- while循环
whlie condition ; do 程序段;done
- until循环
until condition ; do 程序段; done
- for循环
for var in [words...]; do 程序段; done
三种语句与C语言的循环语句有些类似,结尾需要加上done来结束循环语句
函数
语法一:
funcName(){ echo "abc";}
语法二
function funcName(){ echo "abc";}
函数调用时跟C语言不通,不需要小括号,后面参数用空格隔开,代表参数1,参数2.
注意:
- shell自上而下执行,函数必须在使用前定义
- 函数获取变量和shell script类似,
$0代表函数名,舒徐参数通过$1,$2...获取 - 函数内return与C语言中的不通,仅仅表示函数执行状态不代表函数执行结果
- 返回结果一般使用echo、printf,在外面使用
$()、"获取结果 - 如果没有return,函数状态时上一条命令的执行状态、存储在$?中
模块化
模块化的原理是在当前shell内执行函数文件,方式:
source [函数库的路径]
当我们修改完bashrc文件配置好环境变量后,直接运行命令是没有效果的,需要使用source ~/bashrc后才可以使用
常用命令
执行
- shell脚本一般以.sh结尾,也可以没有.第一行需要指定用什么命令解释器来执行
#! /bin/bash
#! /usr/bin/env bash
- 启动方式
# 文件名运行
./filename.sh
# 解释器运行
bash ./filename.sh
#source运行
source ./filename.sh
- 执行过程
1. 字符解析
- 识别换行符、分号(;) 做行的分割
- 识别命令连接符(|| && 管道) 做命令的分割
- 识别空格、tab符 做命令和参数的分割
2. shell展开
- 大括号展开
{a .. e} => a b c d e
{1..3} => 1 2 3
- 波浪号展开
当前用户目录: ~ => $HOME ~/foo => $HOME/foo
指定用户目录 ~fred/foo => 用户fred的$HOME/foo
当前工作目录 ~+/foo => $PWD/foo
上一个工作目录 ~-/foo => $($OLDPWD-'~-')/foo
- 参数展开
间接参数扩展 ${!parameter}
参数长度 ${#parameter}
空参数处理
${parameter: -word} 为空替换
${parameter: =word} 为空替换,并将值赋给$parameter变量
${parameter: ?word} 为空报错
${parameter: +word} 不为空替换
参数切片
${parameter:offset}
${parameter:offset:length}
参数部分删除
${parameter%word} 最小限度从后面截取word
${parameter%%word} 最大限度从后面截取word
${parameter#word} 最小限度从前面截取word
${parameter##word} 最大限度从前面截取word
- 命令替换
- 数学计算 $((..))
- 文件名展开 * ? [..] 外壳文件名模式匹配
3. 重定向,将stdin、stdout、stderr的文件描述符进行指向变更
4. 执行命令
- builtin 直接执行
- 非builtin 使用$PATH 查找,然后启动子进程执行
5. 收集状态并返回
- 调试
1. 普通log,使用echo、printf
2. 使用set命令
3. vscode debug插件
尾记
掌握shell语法可以让重复繁杂的工作变得些许的便利,例如在Linux系统中做项目需要多次运行一串代码,如果代码串很长,难免会有输错的可能,这时我们会按↑来回到这一条指令进行修改,多次的应用会带来或多或少的麻烦,但是将这串指令利用shell编写成脚本,我们只需要运行脚本这个文件,就可以完成指令的输入,会给项目带来许多便利.所以shell也需要多多接触,多加运用.