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截断并不会引用变量
  • 反引号 ` 括主的字符串表示被括住的命令执行输出