Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。 Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
什么是shell解释器
- Shell 运行于内核之上,相对于操作系统内核层级较高,因而被成为壳(Shell单词含义是壳)
- Linux的Shell解释器中最常见的是BASH:bourne-again shell 起源于Stephen R. Bourne 为Version 7 Unix 写的 Bourne Shell ,后经GNU改(重)写为BASH
- UNIX中最常见的shell解释器是KornShell(KSH),POSIX中的shell规范最早参考KSH实现
什么是shell通用语言
Shell通用语言是
- 在POSIX规范(IEEE Std 1003.2 第二章)中定义的
- 命令式的
- 面向过程的
- 解释运行的
- 脚本语言
为什么用BASH
- 许多常见linux发行版采用bash作为默认shell
- 部分UNIX 或类UNIX 操作系统
- 部分linux之外的UNIX也包含bash 比如 苹果的MacOS和freebsd
执行命令
Shell解释器中最基本的用法是执行命令:
输入一条命令列表,按回车执行
vagrant@homestead:~$ echo kingofzihua
kingofzihua
shell 在执行这条命令时,执行了非常复杂的寻找命令的操作,这个我们不需要关心,只需要关心这样可以执行命令就可以了
键盘操作
- 在现代交互式的shell解释器命令行中,左右移动光标,按退格删除光标前的字符,按delete删除光标后的字符
- 在大多数bash的默认配置里按home将光标置于行首,end置于行尾
- 在某些配置里(如macOS)按ctrl+A和ctrl+E移至行首行尾
历史记录和补全
- 在大多数现代shell里有历史记录功能,根据shell的不同和配置不同有不同的用法
- 一般来说使用上箭头向上查找历史记录,右箭头向下查找
- 按tab进行补全,不同shell补全规则和能力不同
作业(job)控制
现代的shell解释器中存在作业控制功能
- 按ctrl+Z 将向当前进程发送SIGSTOP信号,如果当前进程没有实现SIGSTOP的特定逻辑,默认的行为是当前进程暂停并置入后台
- 使用命令fg来使恢复后台进程的前台运行
- 使用命令bg来使暂停的后台进程后台继续运行
- 使用命令jobs来显示后台作业
- 作业号不同于进程号
案例 1
$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.3.0-amd64.deb
# 按ctrl + Z 后会显示
[1]+ Stopped wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.3.0-amd64.deb
$ bg %1 # 这个1 就是上面中括号里面的作业号
#会显示下面这样
[1]+ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.3.0-amd64.deb &
# Redirecting output to ‘wget-log’
$ wait %1 等待任务1的执行 # 可以按ctrl + C退出
$jobs 查看所有后台作业列表
案例 2
# 编辑一个文件
vim wget-log
# 忘记内容了 按 ctrl +Z 将vim 进入后台
# [2]+ Stopped vim wget-log
man vim # 查看vim文档
#退出后将vim 拉入前台
fg %2
# ... 继续编辑
用分号 ; 结束一条命令
和很多语言中的分号一样,shell中的分号也结束一条语句。分号在很多情况下可以代替换行符
#在1行中执行两条命令
$ echo 1; echo 2
1
2
$ for i in 1 2 3; do echo $i ; done
1
2
3
用 & 异步执行一条命令
在命令列表后加一个 & 来后台执行它
$ vim wget-log &
[2] 12316
# 将vim 后台执行没有啥子意义,用fg拉回来
fg %2
Pipeline : | > < >>
- 使用 | 来连接两个命令列表来连接前一个命令进程的stdout到后一个到stdin
- 使用 > 来转发 stdout (或指定任意文件描述符)到文件(使用>>采用追加模式打开目标文件)
- 使用< 来转发文件到stdin (或指定任意文件描述符)
| 管道符
# base64 将一个字符串加密成base64编码 -d:将base64编码后端字符串解析成字符串
$ echo helloword | base64 # 将字符串 helloword输出并连接到 base64进程
aGVsbG93b3JkCg==
$ echo aGVsbG93b3JkCg== | base64 -d
helloword
> 、>> 输出到文件
$ echo helloword > a.txt
$ cat a.txt
helloword
$echo helloword >> a.txt # >> 追加到文件
$ cat a.txt
helloword
helloword
< 输出到前面进程
$ base64 < a.txt # 两个helloword
aGVsbG93b3JkCmhlbGxvd29yZAo=
Heredoc : <<
在命令后使用<<来使用heredoc功能
$ base64 << EOF
> helloword
> EOF
aGVsbG93b3JkCg==
命令列表逻辑 || &&
- Shell中命令返回值为0代表成功,不为0为失败
若命令由于某信号退出(如用户按了ctrl+C发送了SIGINT(值为2)到进程,进程未做处理,按默认行为异常退出)则命令返回值为负信号(以上情况返回值为 -2) - 在命令间使用||和&&,根据前一条命令的返回值决定是否执行后一条命令
Shell变量
- Shell中存在变量,这些变量在当前子Shell作为环境变量,使用export命令导出后在上层shell作为环境变量
- 变量明明规则类似于C的标识符:
若干个下划线,大小写字母和数字,标识符的第一个字符不能是数字 - 与CMD的变量不同,shell的边领名区分大小写
# 注意 变量名和=中间、=后面不能有空格
$ var=kingofzihua
# 我们可以先设置一个变量,后面执行命令,前面的变量会作为后面命令的环境变量
$LANG=en date
引用Shell变量
- 使用{变量名}来引用变量
- {变量名+字符串}使用默认值和替换值
- ${变量名?字符串}提供变量未设置时的错误信息
- ${变量名%%字符串} ${变量名%字符串} ${变量名## 字符串} ${变量名#字符串}截取字符串
Shell引用: "" '' ``
- 双引号 " 括住的字符串不会根据$IFS环境变量截断
- 单引号 ' 括住的字符串不会被$IFS截断并不会引用变量
- 反引号 ` 括主的字符串表示被括住的命令执行输出