本文参与青训营笔记创作活动
学习shell的价值
- Linux服务器的基本操作和管理
- 前端Node.js服务的进程管理、问题排查、资源监控等运维操作
- 使用shell编写TCE、SCM、Docker脚本,完成服务编译和部署
shell基础概念
什么是shell?
- shell是操作系统的最外层,是一个用户跟操作系统之间交互的命令解释器。
- 大多数linux默认的shell命令解释器是 bash(/bin/bash)
- shell独立于内核,是链接内核和应用程序的桥梁,通俗来讲shell是内核周围的外壳
概念
物理终端 => 软件终端tty => 终端模拟器 => shell
- tty 或者说终端最开始指的是获取用户输入并输出的物理设备, 比如电传打字机。在 linux 中是接收用户输入、输出结果的终端仿真软件, 比如我们用的 mac terminal、 iterm2 等, 更强输入辅助功能、画面绘制输出的模拟终端器;
- 而 tty 变成一个
虚拟概念, 是linux的一个程序,每个终端模拟器关联一个虚拟 tty ,和内核打交道。 我们可以在 终端模拟器中输入 tty 查看关联到的虚拟 tty - bash是 shell的一种具体实现, 可以理解成 实例和类的关系
发展
- 除了替代 v6 shell,sh 还有几个优点,把控制流程,循环,变量引入了脚本,提供了一种更具功能性的语言
- 主流 Linux 系统使用的 shell,许多都以它为锚点。
- bash是 sh 的超集,可以直接执行大部分
sh 脚本。 Bash 在兼容 Bourne shell 脚本编程的同时,集成了 Korn shell 和 C shell 的功能,包括命令历史,命令行编辑,目录堆栈(pushd 和 popd),一些实用环境变量,命令自动补全等。
构成
- shell 不仅提供了与内核和设备交互的方法,还集成了一些今天软件开发中通用的设计模式(比如管道和过滤器), 具备控制流程,循环,变量, 命令查找的机制
- 既是命令解释器, 也是一门编程语言, 作为命令解释器, 它提供给用户接口,使用丰富的 GNU 工具集, 第三方的或者内置的, 比如 cd、pwd、exec、test、 netstat 等等
shell语法和命令
| 类型 | 作用域 | 声明方式 | 规范 |
|---|---|---|---|
| 自定义变量 | 当前shell | = | 字符串、整型、浮点型、日期型 |
| 环境变量 | 当前shell及其子shell | export、declare -x | |
| 系统环境变量 | 所有shell | 启动加载 |
父子shell:
自定义变量
- declare的后缀参数:
系统环境变量
| 变量名 | 含义 | 常见操作 |
|---|---|---|
| $0 | 当前shell名称/脚本名称 | $1、$2等可以获取到传入参数 |
| $# | 传入脚本的参数数量 | if[$# -gt1] |
| $* | 传入脚本的所有参数 | |
| $? | 上条命令执行的状态码 | if[$?-eq0] |
| $PS1 | 命令提示符 | export PS1="\u@\h \w >" |
| $HOME | 用户主文件夹 | cd~ |
| $PATH | 全局命令的搜索路径 | PATH=$PATH:[新增路径] |
- 修改默认配置(例如PS1)时,需要通过
vim进入默认的.bashrc文件,修改完成后还需要source重置 - 配置文件加载
- 通过系统用户登录默认运行的shell。
- 非登录交互式运行shell
- 执行脚本运行非交互式shell
如果取得 bash 需要完整的登录流程, 我们称之为 login shell, 比如 ssh 远程登录一台主机。
不需要登录的bash 我们称为 non-login bash, 比如在原来的 bash 中执行 bash开启子进程、执行一些外部命令。
如果修改了配置文件,不会立即生效,需要我们重启终端或者执行 source 命令
运算符和引用
管道
管道与管道符 |,作用是将前一个命令的结果传递给后面的命令
语法:cmd1 | cmd2
要求:管道右侧的命令必须能接受标准行输入才行,比如grep命令、is、mv等不能直接使用,可以使用xargs预处理
注意:管道命令仅仅处理stdout,对于stderr会忽略,可以使用set -o pipefail设置shell遇到管道错误退出
重定向
每个 shell 命令在执行时都会打开三个文件描述符, 文件描述符0、1、2, 分别对应 stdin、stdout、stderr, 这三个文件描述符默认指向 终端输入、终端输出,那么当命令需要获取输入的时候,它会去读取 fd0, 当要输出的时候它会像 fd1、fd2写入, 改变这些描述符指向的行为叫做 重定向
输出重定向符号:
>:覆盖写入文件>>:追加写入文件2>:错误输出写入文件(2>&1 必须写在 > 之后)&>:正确和错误输出统一写入到文件中
输入重定向符号:<、<<(
<< 比较特殊, 表示继续沿用当前的标准输入, 只是当识别到指定的标识符后停止, 将接收到的内容作为 stdin)
判断命令
shell中提供了test、[ ]、[[ ]]三种判断符号,可用于:
- 整数测试
- 字符串测试
- 文件测试
语法:
- test condition
- [ condition ]
- [[ condition ]]
注意:
- 中括号前后要有空格符;
[和test是命令,只能使用自己支持的标志位,<、>、=只能用来比较字符串。- 中括号内的变量,最好都是用引号括起来
[[更丰富,在整型比较中支持<、>、=,在字符串比较中支持=~正则
分支语句
语法1:
if condition ; the
程序段
elif condition ; the
程序段
esle
程序段
fi
语法2:
case $变量in:
"第一个变量内容")
程序段
;;
"第一个变量内容")
程序段
;;
*)
程序段
;;
esac
循环
- while循环
while condition ; do程序段 ; done - until循环
until condition ; do程序段 ; done - for循环
for var in [words. . . ] ;do程序段;done
函数
语法—:
funcName(){echo "abc";}
语法二:
function funcName(){echo "abc";}
注意:
- shell自上而下执行,函数必须在使用前定义
- 函数获取变量和 shell script类似,
$O代表函数名,后续参数通过$1、$2...获取 - 函数内
return仅仅表示函数执行状态,不代表函数执行结果 - 返回结果一般使用
echo、printf,在外面使用$()、``获取结果 - 如果没有return ,函数状态是上一条命令的执行状态,存储在
$?中
模块化
模块化的原理是在当前shell内执行函数文件,方式:source [函数库的路径]