Shell
Unix操作系统分为两个部分:内核和应用,内核是UNIX系统的核心并且驻留内存,日常事务比如直接与硬件通信等都由内核完成。除了内核,有一些基本模块也是驻留内存的,这些模块完成重要的功能,比如输入/输出管理,文件管理内存管理等待。
Unix系统的其他部分保存在磁盘中,在需要时调入内存,绝大多数UNIX命令时保存在磁盘上的程序,在需要时调入内存,在用户输入一个命令时相应的程序就被调入内存。
Shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell 的本质。Shell 本身并不是内核的一部分,它只是站在内核的基础上编写的一个应用程序,然而 Shell 也有着它的特殊性,就是开机立马启动,并呈现在用户面前;用户通过 Shell 来使用 Linux,不启动 Shell 的话,用户就没办法使用 Linux。
sehll可以用来执行命令,文件名替换,I/O重定向和管道符处理,环境控制,后台计算以及运行shell脚本,/etc/passwd决定了用户登录后执行的shell程序,有些特殊的用户,可以不是shell程序
shell解析用户命令和进程的退出
shell解析用户命令
- 创建子进程执行用户命令
- shell等待命令子进程退出
- 命令子进程退出,发送SIGCHLD信号给shell
- shell在信号处理函数中处理子进程退出
shell进程退出
- 发送SIGCHLD信号给login进程
- login进程处理SIGCHLD信号
- 退出,发送SIGCHLD信号给init进程
- init进程处理SIGCHLD信号,重新fork/exec一个getty进程

shell语言
Shell 命令的基本格式如下:
command [选项] [参数],与前面所学的命令十分相像,如果有多行单条命令,则要在行尾以\
结束,shell也有扩展符,大体上与C相似,就不复述了。
shell的命令解析过程:
- 完整的命令解析过程
- tilde是~表达式展开
- 变量替换
- 命令展开是重音符的命令展开
- 单词划分利用$IFS变量分割
- 寻找命令
显示信息echo
echo用来显示信息到终端上,如果需要格式化输出请使用printf
echo hello there

有些shell的元字符对shell来说有特殊含义,这时候就有引用字符来消除元字符的特殊含义,除了反斜杠外还提供了:' '
," "
。
双引号:
双引号可以忽略大多数字符的特殊意义,除了 $,单引号和双引号,此外双引号还保留了空白字符。
单引号:
单引号在双引号基础上加强了,除了单引号外,任何符合的特殊意义都被消除,单引号同样保留空白符,除此之外还有一个非常重要的特性,包含在单引号的字符串变成1个单个的参数,空格也失去了作为参数分隔符的含义。
shell变量
变量是任何一种编程语言都必不可少的组成部分,变量用来存放各种数据。脚本语言在定义变量时通常不需要指明类型,直接赋值就可以,Shell 变量也遵循这个规则。
在 Bash shell 中,每一个变量的值都是字符串,无论你给变量赋值时有没有使用引号,值都会以字符串的形式存储。
这意味着,Bash shell 在默认情况下不会区分变量类型,即使你将整数和小数赋值给变量,它们也会被视为字符串,这一点和大部分的编程语言不同。例如在C语言或者 C++ 中,变量分为整数、小数、字符串、布尔等多种类型。
变量的定义
shell中的变量分为环境变量和局部变量,其中环境变量也被称为标准变量,拥有为系统所知道的变量名,被用于定义系统基本的特征,环境变量会传递给子进程(fork)。而局部变量就由用户自定义使用。
set命令显示所有变量,export命令显示所有环境变量。
Shell 支持以下三种定义变量的方式,注意,三种的等号两侧都是不能有空格的
- variable=value
- variable=’value’
- variable=”value”
export VAR=xxx则用于添加环境变量
使用变量
使用一个定义过的变量,只要在变量名前面加美元符号$即可,如:
author="aaa"
echo $author
echo ${author}
变量名外面的花括号{ }是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,推荐都加上,这是个良好的编程习惯.
其中有一些标准变量:
- HOME变量记录用户主目录
- PATH变量给出外部程序的搜索路径,在win中也有类似的存在
- IFS变量定义扩展命令参数时的分隔符
命令参数展开
shell在解释命令时,有一个重要的步骤是展开变量得到命令参数
例如 ls -al *
- shell在解释这条命令时
- ls是命令,special builtins 到functions 到builtins 到export command去查找
- -al是参数
- *需要展开
shell内部将对参数的展开:
- -开头当成选项
- 双引号、单引号、重音符号开头作为字符串
- $开头作为变量
- <>作为重定向符号
- |作为管道符号
- 其余字符串如果包含*?[]需要做路径匹配展开
特殊字符
以单引号’ ‘包围变量的值时,单引号里面是什么就输出什么,即使内容中有变量和命令(命令需要反引起来)也会把它们原样输出。这种方式比较适合定义显示纯字符串的情况,即不希望解析变量、命令等的场景。
以双引号” “包围变量的值时,输出时会先解析里面的变量和命令,而不是把双引号中的变量名和命令原样输出。这种方式比较适合字符串中附带有变量和命令并且想将其解析后再输出的变量定义。
重音符号表示一个内嵌命令,要先执行,然后得到输出作为参数,双引号内的重音符号要先执行。$()
也可以实现同样的效果,而且从视觉上说不容易与单引号和重音符号弄混淆。
有一个建议:
如果变量的内容是数字,那么可以不加引号;如果真的需要原样输出就加单引号;其他没有特别要求的字符串等最好都加上双引号,定义变量时加双引号是最常见的使用场景。
除了单引号双引号重音符号外,还可以使用分号进行命令排序或者使用括号进行命令编组,需要后台运行的话,使用&符号,后面会有介绍。
进程管理
ps
在学习后台运行之前,先来学习如何管理进程,ps命令显示用户当前活动进程的信息,如果学会了systemd的话可以一起配合使用(自行了解)。
- PID:进程ID数
- TTY:控制该进程的用户终端号
- TIME:用户进程以及运行的时间(以秒计)
- COMMAND:命令名称
参数 | 选项 |
---|---|
-a | 显示所有终端机下执行的进程,除了阶段作业领导者之外,不包括无终端进程。 |
-f | 显示UID,PPIP,C与STIME栏位。 |
-e | 显示所有进程。 |
-H | 按照树型显示 |
-j | 按照job形式输出 |

nohup
nohup “command”&
如果想要在用户退出系统后继续执行后台进程,则可以使用nohup命令,他可以让进程免于被终止信号终止,了解即可。
kill
在知道如何查看用户进程后,就可以使用kill来停止那些想要停止的程序,kill命令通过向进程发送信号来控制,默认发送的信号为15(SIGTERM)信号,强制停止的话,则使用9(SIGKILL)信号。
信号类似于硬件中断,Ctrl-c快捷键类似发送SIGINT信号,而Ctrl-d类似发送EOF,意思是输入关闭。
参数 | 选项 |
---|---|
-l | 列出所有信号 |
-1 | 除了init进程和自身外关闭所有进程 |
-s | 指定发送信号 |
-u | 指定用户 |

trap
trap是一个shell内建命令,它用来在脚本中指定信号如何处理。比如,按Ctrl+C会使脚本终止执行,实际上系统发送了SIGINT信号给脚本进程,SIGINT信号的默认处理方式就是退出程序。如果要在Ctrl+C不退出程序,那么就得使用trap命令来指定一下SIGINT的处理方式了。trap命令不仅仅处理Linux信号,还能对脚本退出(EXIT)、调试(DEBUG)、错误(ERR)、返回(RETURN)等情况指定处理方式。
格式为:
trap “command” signal numbers 将执行双引号中的命令串。
trap '' TERM 则是忽略SIGTERM信号
trap - TERM 用来恢复SIGTERM信号缺省处理
如果在编写shell脚本的话,trap最好放在开头第一个非注释行。另外,在trap语句中,单引号和双引号是不同的,当shell程序第一次碰到trap语句时,将把commands中的命令扫描一遍。此时若commands是用单引号括起来的话,那么shell不会对commands中的变量和命令进行替换, 否则commands中的变量和命令将用当时具体的值来替换。
在实际使用中,可以使用下面的命令来创建临时文件,并在退出时候(无论以那种形式)时将临时文件删除。
其他一些命令
Bash在执行命令后,会在内存中记录所有使用的命令,当用户退出登录,所有命令保存在~/.bash_history文件中,而history命令则列出到目前为止,执行的所有命令。
fc是一个builtin命令
- fc first last 命令先编辑从first到last的命令,然后执行
- fc –s cmd cmd是history的命令编号,执行该编号任务
alias是一个builtin命令,相当于为命令设置别名。
tee命令分离输出,同时输出到标准输出和文件
参数 | 选项 |
---|---|
-a | 追加到文件 |
-i | 忽略中断信号 |
例如ls -al | tee dir.list
以上内容了解即可,接下来我们不会按照课本上的顺序,而是先将shell学完。
终端命令
stty设定终端模式
- stty –echo禁止回显,输入口令时
- stty echo打开回显
tput控制终端输出缓冲
- tput clear清屏
- tput cup row column移动光标到row行column列