%%
# 纲要
> 主干纲要、Hint/线索/路标
# Q&A
#### 已明确
#### 待明确
> 当下仍存有的疑惑
**❓<font color="#c0504d"> 有什么问题?</font>**
# Buffer
## 闪念
> sudden idea
## 候选资料
> Read it later
%%
# 关于 shell
> shell 俗称"壳",表示其"区别于内核",是用户与操作系统内核进行交互的桥梁。
shell 是一个**命令行解释器**,提供了一个**命令行界面**,同时也是一种**脚本语言**。
- **==命令行解释器== (command line interpreter, CLI)**
- **==命令行界面==(command line interface, CLI)**:
- **==脚本语言==**
shell 提供了 "shell 命令行" 作为用户与操作系统进行交互的接口,其核心功能是作为一个**命令行解释器**,负责**解释用户在命令行界面输入的命令**,**并在内核中执行相应的操作**。
shell 同时提供了一个**命令行界面**,**供用户输入命令、显示命令执行的输出**等。命令行界面只允许输入/显示文本。
shell 也作为一种脚本语言,提供了一个**编程环境 (相关语句和语法)**,支持**脚本编写**。
### shell 的实现
Linux 中有许多种 **shell 实现**,包括:
- **==sh==**(Bourne Shell):
- Unix 系统最初的**标准 Shell** (即最原始版本),在现代系统上通常是**指向系统默认 shell 的一个符号链接**。
- **==Bash==**(Bourne Again Shell):
- **最常见的 Linux Shell**,是许多 Linux 发行版的**默认 Shell**。<br>bash 是为 GNU 项目所编写的 Unix Shell,基于 Bourne Shell 的同时吸收了 C shell 和 Korn shell 的一些特性,其完全兼容 Bourne shell,用 Bourne shell 编写的脚本不加修改就可以在 bash 中执行。
- **zsh (Z Shell)**:
- 类似于 Bash,但提供了额外的功能,如更好的自动完成和主题支持。
- **csh 和 tcsh**:
- 以 C 语言风格的语法而闻名。
> ![[_attachment/02-开发笔记/11-Linux/shell 相关/shell 基本说明.assets/IMG-shell 基本说明-95223BF2F568ACDC74B9858A595E0A8B.png|581]]
<br>
### shell 程序
**shell 的可执行程序**默认都位于 `/bin` 目录下,例如 `/bin/sh` 与 `/bin/bash`:
- `/bin/sh`: 在早期 Unix 系统上即是 Bourna shell,而 **Linux 系统上**通常都将 `sh` 作为一个**软连接**,链接到 **系统默认 shell**
- **Debian、Ubuntu 系统中的默认 shell 是 dash**;
- CentOS 系统中的默认 shell 是 bash。
- `/bin/bash`:**Bash Shell 的可执行程序**。
> [!NOTE]
>
> 查看 sh 路径:可通过 `which sh` 查看 `sh` 所在路径,再通过例如 `ls -l /usr/bin/sh` 的指令查看`sh`的指向。
>
> ![[_attachment/02-开发笔记/11-Linux/shell 相关/shell 基本说明.assets/IMG-shell 基本说明-AA529CBF75826FB44C3270F40951A037.png]]
>
> ![[_attachment/02-开发笔记/11-Linux/shell 相关/shell 基本说明.assets/IMG-shell 基本说明-7628A81662180709FD7811E565318810.png]]
>
>
<br>
## 命令行提示符
shell 命令行界面下显示了"**命令行提示符**" (prompt),即位于命令输入行头部位置的一段文本。
命令行提示符提供了:**当前用户名**、**系统的主机名**、**当前工作目录`pwd`**。
```shell
# 普通模式下的命令行提示符:
username@hostname:pwd$
# root模式下的命令行提示符:
root@hostname:pwd#
```
结尾的 `
是一个普通用户的提示符结束符;对于 root 用户则通常是 `#`。
![[_attachment/02-开发笔记/11-Linux/shell 相关/shell 基本说明.assets/IMG-shell 基本说明-FEACAA99E235F2AB07C694AE8D63F89D.png]]
在 Bash 中,提示符是通过环境变量 `PS1` 定义的。
可以编辑 `~/.bashrc` 或 `~/.bash_profile` 文件来改变 `PS1` 的值,从而定制提示符。例如:
```shell
export PS1='\u@\h:\w\$ '
```
其中 `\u` 表示用户名,`\h` 表示主机名,`\w` 表示当前工作目录,`\
为结束符。
<br><br>
## 运行/启动 shell
> 术语:"**shell 会话**"" == "**shell 进程**" == "**shell 实例**"
用户在登录到系统时,会启动一个 "**登录式 shell**",**具体启动的 shell 程序 (bash、dash 等) 取决于用户账户配置文件 `/etc/passwd` 中该用户配置的最后一个字段**。
### 默认 Shell
- **默认的交互式 shell**(default interactive shell)也即 **==登录 shell==**
- 用户登录终端时默认启动的具体 shell 程序(bash/dash 等)由**用户账户配置文件 `/etc/passwd` 中该用户配置的最后一个字段指定**。
- **默认的系统 shell** (default system shell):即 `sh` (`/bin/sh`) ,用于那些 **==需要在启动时使用的系统 shell 脚本==**。
### 当前 shell
在 shell 会话 (命令行界面) 中,环境变量 `$0` 为 **==当前 shell 的名称==**。可通过 `echo $0` 命令查看
> 如果在 shell 脚本中查看该环境变量,则显示的是"**该 shell 脚本**"的名称。
## shell 的命令搜索目录
环境变量 `PATH` 定义了 shell 查找 **可执行文件** 的搜索目录列表。
当在命令行中输入一个命令时,shell 会**按照 `PATH` 环境变量中罗列的顺序,依次从这些目录中搜索可执行命令**。
> 例如,如果 `PATH` 的值为 `/usr/local/bin:/usr/bin:/bin`,shell 首先会在 `/usr/local/bin` 中查找命令,如果没找到,接着在 `/usr/bin` 查找,以此类推。
#### PATH 环境变量
环境变量 `PATH` 是一个包含**由冒号 (`:`) 分隔**的**目录路径的字符串**。
每个路径指向一个文件系统中的目录,Shell 会在这些目录中**查找可执行文件**。
- **查看当前 PATH**:使用 `echo $PATH` 命令可查看环境变量 `PATH` 的值。
- **修改 PATH**:
- **临时修改**:使用 `export PATH=$PATH:/new/path` 命令临时修改,该更改**仅对当前 shell 会话有效**。*。
- **永久修改**:要永久修改 `PATH`,需要在系统或用户的登录配置文件或 shell 配置文件中添加上述 export 命令,并重新加载配置文件触发生效。发生效。
<br><br>
# 关于 bash
Bash(Bourne Again SHell)是**最常见的一种 Unix Shell**。
bash 是为**GNU 项目所编写的 Unix Shell**,作为原始 Bourne shell 的自由软件替代品。
bash 在基于 Bourne Shell 的同时吸收了 C shell 和 Korn shell 的一些特性,其**完全兼容 Bourne shell**,用 Bourne shell 编写的脚本不加修改就可以在 bash 中执行。
![[_attachment/02-开发笔记/11-Linux/shell 相关/shell 基本说明.assets/IMG-shell 基本说明-5FE6286C1D7DB5C82755E0847A0ED14F.png]]
Bash 的功能特性:
- **命令历史和补全**:Bash 会输入的历史命令,可以通过上下箭头键浏览历史记录,支持反向搜索历史命令
- **命令补全**:通过 `Tab` 键可以自动补全命令和文件名。
- **脚本编写**:Bash 同时是一种流行的脚本语言,支持编写脚本以自动化复杂的任务。
Bash 脚本支持变量、条件判断、循环控制结构、函数等编程特性。
- **命令别名**:可以为常用的长命令创建简短的别名。
- **作业控制**:支持将命令放入后台执行,以及将后台命令带回前台。
- **环境配置**:用户可以通过编辑 `~/.bashrc`、`~/.bash_profile` 等配置文件来定制自己的 bash shell 环境。
- **兼容性**:保持对旧版 Bourne shell 脚本的兼容性,同时扩展了其功能。
<br>
## `bash` 命令
`bash [options] [command_string | file] ` **启动新的 bash 会话**(进程)
- `-c`:将第一个非选项的**参数" `command_string`" 作为需要执行的命令**,在新启动的 bash 中执行。
- 如果 `command_string` 之后跟有参数,则**第一项参数**将作为**bash 的名称赋给环境变量 `$0`**。<br>其余参数作为位置参数传递给 `command_string` 命令。
- `-i`:启动一个交互式 shell 会话。(可用于在脚本中使用`bash -i`启动交互式 shell)
- `-l`, `--login`:以 "**登录 shell**" 的方式启动 Bash,会使得 Bash 读取和执行**登录配置文件**。
- `-s`:从标准输入读取命令。通常与管道配合使用,例如:`echo 'echo Hello World' | bash -s`
- `-e`:如果**任何命令返回非零退出状态**,则**立即退出 shell**。通常用于脚本中,以确保脚本在出错时停止执行。
- `-x`:在执行命令前打印命令及参数。通常用于调试,例如:`bash -x script.sh`
- `-v`:在读取输入行时打印 shell 输入行,通常用于脚本调试。
- `--norc`:作为交互式非登录 shell 启动 bash 时,**不读取 `~/.bashrc` 配置文件**。
- `--noprofile`: 作为登录 shell 启动 bash 时,不读取 `/etc/profile` 和 `~/.bash_profile` 等配置文件。
```shell
bash -c 'echo Hello World' # 执行命令
bash my_script.sh # 执行脚本
bash -l myscript.sh # 以"登录shell"的方式启动bash, 并执行该脚本
bash -e myscript.sh # 如果脚本中任何命令出错(返回非零退出状态码), 则立即退出bash.停止执行
bash --norc myscript.hsh # 启动bash时不读取 `~/.bashrc` 配置文件.
```
<br><br><br>
# shell 命令
## shell 内部命令与外部命令
shell 命令可以分为内部命令和外部命令。
- ==**内部命令==(Build-in commands)**:内部命令是**shell 本身的一部分**,与 shell 编译成一体,**直接由 shell 程序执行**,<br>**无需调用外部程序文**件,也**不需要创建子进程来执行**。
- 例如 `cd`,`echo`,`exit`,`history` , `type`,`set`,`unset`,`alias` 等。
- **==外部命令==(文件系统命令)**:外部命令不属于 shell 的内置部分,而是存放在文件系统上的**可执行文件**。<br>当执行外部命令时,会从 shell 中创建一个**新的子进程**。
- 例如 `ps`,`ls`,`grep`,`awk`,`cat` 等。
- shell **仅在 `PATH` 环境变量指定的路径**中搜索外部命令。
- (通常存放在 `/usr/bin`,`/usr/sbin` 等目录下,也可以在其它任何位置)
#### 区分内部命令与外部命令
- 通过 `help` 可查看**内部命令**的说明。
- 通过 `type` 可查看**命令的类型**,对于外部命令会显示其对应的文件路径。
- 通过 `which` 可查看**外部命令**对应的文件路径。
有些命令有内、外部多种实现。通过 `type -a` 可查看命令的两种实现,
例如 `echo`、`pwd`、`set` 等。
![[_attachment/02-开发笔记/11-Linux/shell 相关/shell 基本说明.assets/IMG-shell 基本说明-3002E2376CE2B443EE22C2DDD86AB9A3.png]]
对于有多种实现的命令,如果想使用其**外部命令实现**,直接**指明对应的文件即可**。
例如,要使用外部命令 `pwd`,可以输入 `/usr/bin/pwd`。
> [!NOTE]
>
> 通过 `help` 命令可一览所有 shell 内置命令
>
> ![[_attachment/02-开发笔记/11-Linux/shell 相关/shell 基本说明.assets/IMG-shell 基本说明-A0B441A63D6E9B231730AA9C71E6F740.png|629]]
>
>
<br>
## 命令行选项与参数
shell 命令中的选项(option)与参数(arguments)是运行命令或脚本时**传递的不同类型的输入值**:
- **==选项==(option)**:通常用来**调整、控制命令行程序的行为**,启用或禁用某些功能。选项的形式包括:
- 以单个连字符 `-` 起始的短选项(例如`-l`,`-r` 等)
- 以两个连字符 `--` 起始的长选项(例如`--version`,`--all` 等)
- 示例:`ls -l`
- **==参数==(arguments)**:参数是**传递给命令的实际数据或指令**,用于提供执行命令所需的数据,例如文件名、数值等数据。示例:`cp source.txt destination.txt`
**选项后面可以带有参数**,即该选项所需的参数值。例如:`./testing.sh -a test1 -b -c -d test2`
> [!NOTE]
> 命令行参数是在命令/脚本名之后出现的各个单词,其中,以连字符(`-`)或双连字符(`--`)起始的参数因其能够改变命令的行为,称作命令行选项。所以,**命令行选项是一种特殊形式的命令行参数**。
>
常用 Linux 命令行选项:
>
> ![[_attachment/02-开发笔记/11-Linux/shell 相关/shell 基本说明.assets/IMG-shell 基本说明-3F913F966093E60FED0D6AE5EABF3FA9.png|643]]
<br><br>
## 退出状态码
在 Shell 中,命令的退出状态码(或退出码)是一个用于**表示命令执行成功或失败**的数字。
shell 中运行的每个命令都使用**退出状态码**来告诉 shell 自己已运行完毕,并告知命令执行成功或失败。
退出状态码是一个 `[0, 255]` 之间的整数值,**在命令结束运行时**由其传给 shell。
在 Unix 和 Linux 系统中,状态码遵循特定的约定:
- **0 表示成功**:如果命令执行成功且没有发生错误,则**退出状态码通常为 0**。
- **非 0 表示失败**:如果命令执行失败或出现错误,退出状态码是一个非 0 值。不同的值可以表示不同类型的错误。
可以使用特殊变量 `$?` 来查看**最后一个已执行命令**的退出状态码。**对于需要进行检查的命令,必须在其运行完毕后立刻查看或使用`$?`变量**。例如:
```shell
$ somecommand
$ echo $?
```
对于 shell 脚本而言,默认会**以脚本中的最后一个命令的退出状态码**退出。
`exit <num>` 命令允许结束在脚本结束时指定一个退出状态码,也可以使用一个变量作为 exit 命令的参数。
> 常用状态码:
> ![[_attachment/02-开发笔记/11-Linux/shell 相关/shell 基本说明.assets/IMG-shell 基本说明-C52445C1F08C96E99E3AA401A7FD260C.png|511]]
<br><br><br>
# shell 作业
在 Shell 中,**"作业"(Job)** 是指**由 shell 管理的在 "前台或后台" 运行的命令或进程**(**==由当前 shell 启动的==**)
shell 作业包括两种:
- **前台作业**:始终占用当前终端直至被完成或停止的作业,该期间用户不能与 shell 交互,直至作业结束。
- 一个 shell 会话中**一次只能有一个前台作业**,它占据终端直接与用户交互,没有作业号。
- **后台作业**:以后台模式 (`&`) 从当前 shell 中启动的作业,作为独立进程在后台运行。
- 每个 "后台作业" 都会被 shell 唯一地分配有一个**作业号**(从 1 起)。
> [!caution] **后台作业与终端绑定**,**==当终端会话退出时,所有后台进程也会随之退出==**。
>
> 原因:终端被注销或退出时,会发送 `SIGHUP` 信号给其关联的所有子进程(包括后台进程)。
>
> 如要分离后台进程与终端的关联,需使用 `nohup` 搭配 `&`:`nohup command [args...] &`
>
<br>
### shell 作业控制
Shell 提供了作业控制的功能,例如:
- `jobs`:**列出当前会话中的所有作业及其状态**(运行中、已停止等)。
- `fg [job]`:**以前台模式运行后台作业**,即将后台作业带到前台来继续执行。
- `bg [job]` :**以后台模式重启被停止/暂停(Stopped)的作业**。即该作业将继续以后台模式运行。
- `kill`:发送信号给作业,通常用于终止作业。
参见[[02-开发笔记/11-Linux/Linux 命令行/Linux-进程相关命令|Linux-进程相关命令]]
<br>
### 后台模式
Linux 中支持 **在后台启动运行一个进程**, shell 会立即**返回命令行提示符**,允许用户继续执行其他命令,而后台作业则在后台运行。
以 "后台模式" 运行一个进程,只需在命令后**添加 `&` 符号**,该进程将作为一个 **==独立进程==运行在后台。**
当进程被置入后台时,会打印 `[n] PID` 格式的信息: **后台作业号 `n`**,以及**后台作业的进程 PID**。
![[_attachment/02-开发笔记/11-Linux/shell 相关/shell 基本说明.assets/IMG-shell 基本说明-62C5002533D41E34AD089406EB43560F.png|405]]
当后台进程结束时,终端上会显示如下形式的一条消息:
`[1]+ Done ./backgroundscript.sh`
其指明了作业号、作业状态(Done)、启动该作业的命令(去除了&)。
> [!NOTE] 后台作业结束信息可能会 "**直到下次执行能让 shell 生成命令行提示符的操作(如按下 Enter 键)时**" 才显示。
> [!caution] **后台进程运行时,==默认仍会占用当前 shell 终端显示器==来显示 STDOUT 和 STDERR 消息。**
<br><br>
# 参考资料
# Footnotes