Shell命令中重定向与管道的概念

# Shell命令中重定向与管道的概念

在Linux系统管理中,Shell命令经常会使用重定向来定义命令的输入和输出。笔者在实现后台服务运行时,发现重定向的应用非常重要,所以总结了Shell中重定向的概念与应用。

## 0. 基本概念准备

### 0.0 Linux命令执行过程

![Shell命令执行过程](http://images.cnblogs.com/cnblogs_com/hongyanee/536427/o_shell_proc.jpg)

对于任何一个Shell命令,都如上图的执行过程。首先从文件(Linux中,设备也是文件,一切都是文件)中读取标准输入;然后执行命令;如果执行成功则将标准输出定向到文件中,如果执行失败则标准错误定向到文件中。

### 0.1 文件描述符

Linux为打开的文件而分配了文件描述符,通过对文件描述符的操作来操作文件。Linux系统本身会占用三个标准的文件描述符,0-2;而用户可以自定义的是3-ulimit,ulimit是可以自定义大小的数。

Linux系统的3个标准文件描述符分别是:

- 0  standard input. 标准输入,默认是键盘设备,也可以是一般文件。
- 1  standard output. 标准输出,默认是监视器,也可以是一般文件。
- 2  error output. 错误输出,默认是监视器。

### 0.2 重定向方向符号

重定向的方向符号用大于符号(>)和小于符号(<)组合而成。意义分别如下:


- < 输入符号。例如```command < input.file```的意义是将command的标准输入重定向为input.file。
- > 输出符号。例如```command > output.file```的意义是将command的标准输出重定向为output.file。
- >> 追加输出符号。例如```command >> output.file```的意义将command的标准输出以追加的方式重定向到output.file。

上面例子中,```command > output.file```会覆盖output.file文件,而```command >> output.file```将输出追加到output.file中。

### 0.3 Shell中的&符号

&符号在Shell中有两种比较常见的方式。

- **当&符号在命令的最后时,作为后台执行命令的标记。**例如```command &```,command将在后台工作。
- **当&符号后面跟数字时,&n表示文件描述符n代表的文件。**例如```command >&n```,表示将标准输出重定向到文件描述符n代表的文件中。

- **当&符号后面跟-时,>&-表示关闭输出设备,<&-表示关闭输入设备。**。

## 1. 重定向的一般用法

### 1.0 输入重定向

| 命令行 | 意义 |
| ------ | ---- |
| command < file.in | command命令以file.in作为标准输入 |

### 1.1 输出重定向

| 命令行 | 意义 |
| ------ | ---- |
| command > file.out | 把标准输出重定向到文件file.out中 |
| command >> file.out | 把标准输出以追加方式重定向到文件file.out中 |
| command < file.in > file.out | 以file.in为输入,把标准输出重定向到文件file.out中 |
| command 2 > file.err | 把标准错误重定向到文件file.err中 |
| command 2 >> file.err | 把标准错误以追加方式重定向到文件file.err中 |
| command > file.out 2>&1 | 把标准输出和错误一起重定向到文件file.out中 |
| command >> file.out 2>&1 | 把标准输出和错误一起以追加方式重定向到文件file.out中 |

### 1.2 绑定重定向

| 命令行 | 意义 |
| ------ | ---- |
| command >&m | 把标准输出重定向到文件描述符m中 |
| command <&- | 关闭标准输入 | 
| command 0>&- | 关闭输入设备 |
| command << delimiter | 从标准输入中读入,直到遇见delimiter分界符 |

## 2. 重定向的特殊用法

### 2.0 重定向标准错误

重定向到空设备,```command 2> /dev/null```,将标准错误输出到空设备。

&符号表示文件:```command > file.out 2>&1```,将标准输出重定向到文件file.out,同时将标准错误重定向到文件标识符为1的文件中。由于文件标识符为1的文件正是标准输出,而标准输出已经重定向到文件file.out,因此上面这条命令会将标准输出和标准错误都重定向到文件file.out。

### 2.1 exec

exec命令可以在新的shell环境中执行command命令。```exec command```,可以看成是启动了新的shell,在新的shell中执行command命令,实际上并没有。

例子1:

```bash
#!/bin/bash

exec 3<&0 0test.sh; #打开test.sh可读写操作,与文件描述符3绑定

while read line<&3
 do
    echo $line;  #循环读取文件描述符3(读取的是test.sh内容)
done

exec 3>&- #关闭文件的,输出绑定
exec 3<&- #关闭文件的,输入绑定
```

## 3. Shell中管道(PIPE)的概念

管道的命令操作符是'|',可以用来连接多个个命令。例如```command1 | command2 | command3```。管道的概念是将前一个命令的标准输入作为后一个命令的标准输出,如下图所示:

![Shell管道原理](http://images.cnblogs.com/cnblogs_com/hongyanee/536427/o_pipe.png)

上述命令的执行过程是这样的:

1. 首先执行command1,执行完成后标准输出并不输出,而是作为command2的标准输入;
2. 将command1的标准输出作为command2的标准输入,执行command2,且将command2的标准输出作为command3的标准输入输入。
3. 将command2的标准输出作为command3的标准输入,执行command3,输入command3的标准输出。

**如果其中有命令执行错误会怎么样呢?**

PIPE中命令串行执行,如果遇到错误,则继续执行。

1. 如果command1运行失败,屏幕打印标准错误,然后继续运行```command2 | command3```。
2. 如果command1执行成功并将标准输出作为command2的标准输入,然后执行command2。如果command2执行失败,屏幕打印command2的标准错误,并且继续执行command3。


## 参考:

[Linux shell的标准输入、输出和错误](http://blog.csdn.net/cjfeii/article/details/10084343)

[linux shell数据重定向(输入重定向与输出重定向)详细分析](http://www.cnblogs.com/chengmo/archive/2010/10/20/1855805.html)

[linux命令后台运行](http://www.cnblogs.com/lwm-1988/archive/2011/08/20/2147299.html)

[Shell管道命令(pipe)使用及与重定向区别](http://www.jb51.net/LINUXjishu/32565.html)

原文地址:https://www.cnblogs.com/hongyanee/p/3445068.html