# Shell基础

## Shell 基础

### Shell 与终端

当Shell启动时，操作系统为它提供三个文件来工作：`stdin`、`stdout`和`stderr`。当从终端运行时，`stdin`连接到键盘输入。你写的内容被传递到终端。这通过一个称为电传打字机或`tty`的文件发生。`stdout`和`stderr`也连接到`tty`，这就是为什么你运行的任何命令的输出和错误都会显示在终端中。

![](/files/4fmz2yByGM2uy4QB5WJB)

你打开的每个终端都会通过`tty`分配一个新文件，这样来自一个终端的命令不会破坏另一个终端的命令。你可以通过`tty`命令找出你的终端连接的文件：

```bash
$ tty
/dev/pts/0
```

### 管道（Pipes）

![](https://drawings.jvns.ca/drawings/pipes.png)

管道，`|`，将两个进程连接在一起。它表示对[pipe()](https://man7.org/linux/man-pages/man2/pipe.2.html)的系统调用，它所做的只是为进程重定向`stdin`和`stdout`。

![$ echo ls | bash](/files/P413W1QF8seapm1LNoA3)

上图是一个轻微的简化，用于解释管道重定向：

* 上层的bash分叉另一个连接到`tty`的bash，它产生`ls`的输出
* 由于上层的bash是从下层分叉的，它继承了下层的文件描述符
* 下层的bash没有分叉新进程，因为`echo`是内置命令

![$ ls -ail | sort -nr -k 6 | head -n 1 | cut -f 9 -d ' '](/files/o5S6Wz4dThmMkFNREKxV)

注意`stderr`总是直接路由到`tty`。你可以在管道之前切换流，并将`stderr`而不是`stdout`重定向到管道。

```bash
$ ./script.sh 2>&1 >/dev/null
```

### 变量

**局部变量**是你在shell中创建的变量。它们是局部的，因此不会传递给子进程（记住，每个非内置命令都在一个新的shell中，没有这些局部变量）。

**环境变量**（`env` vars）类似于全局变量。它们被传递给子进程。但是，子进程中环境变量的更改不能传递给父进程（记住，子进程和父进程之间除了退出码外没有通信）。

```bash
$ env
TERM=xterm
TMPDIR=/tmp
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
LANG=en_US.UTF-8
SHLVL=1
HOME=/root
LANGUAGE=en_US:en
LESSOPEN=||/usr/bin/lesspipe.sh %s
_=/bin/env
```

### Shell 类型

#### Bash (Bourne Again Shell)

* 最常用的Linux shell
* 功能丰富，兼容性好

#### Zsh (Z Shell)

* 更现代化的shell
* 强大的自动补全功能

#### Fish (Friendly Interactive Shell)

* 用户友好的shell
* 智能建议和语法高亮

#### Sh (Bourne Shell)

* 最基础的shell
* 所有shell的兼容基础

### Shell 脚本基础

```bash
#!/bin/bash

# 注释
# 变量赋值
NAME="World"

# 使用变量
echo "Hello, $NAME!"

# 条件语句
if [ "$NAME" == "World" ]; then
    echo "Greetings, World!"
else
    echo "Hello, $NAME!"
fi

# 循环
for i in {1..5}; do
    echo "Count: $i"
done

# 函数
greet() {
    echo "Hello, $1!"
}

greet "Alice"
```

### 常用Shell命令

```bash
# 查看当前shell
$ echo $SHELL
$ echo $0

# 切换shell
$ zsh
$ bash

# 查看历史命令
$ history
$ history | grep "pattern"

# 重复上一个命令
$ !!

# 重复包含特定模式的命令
$ !pattern

# 查看当前工作目录
$ pwd

# 改变目录
$ cd /path/to/directory

# 列出文件
$ ls -la

# 创建目录
$ mkdir new_directory

# 删除文件
$ rm file.txt
$ rm -rf directory/  # 递归删除目录
```

### Shell 配置文件

* `~/.bashrc` - Bash的配置文件
* `~/.bash_profile` - 登录时执行的配置
* `~/.profile` - 通用配置文件
* `/etc/bashrc` - 系统级配置文件

## 参考资料

* [How Unix Works: Become a Better Software Engineer](https://neilkakkar.com/unix.html) - 深入了解UNIX工作原理
* [Bash Reference Manual](https://www.gnu.org/software/bash/manual/) - Bash参考手册
* [Advanced Bash-Scripting Guide](https://tldp.org/LDP/abs/html/) - 高级Bash脚本编写指南


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gitbook.cdxiaodong.life/linux-an-quan/overview/shell.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
