数据流,就是数据传输的通道。在Linux中,一个程序启动时,将会自动开启三个数据流通道:标准输入流、标准输出流、标准错误流。本文详细介绍标准数据流的概念及其重定向的使用。
数据流的简单理解
想象一下,凌晨一点,你似乎完全没有困意,坐在电脑前疯狂地输入一条条的命令,屏幕上滚动的字符告诉你,程序正按你预想的方式执行。突然,一段红色的文字打断了你的思路:程序报错了。
在上面这个场景中,你从键盘输入的信息就是输入流,在屏幕上打印出来的提示信息就是输出流,而红色的报错就是错误流。
数据流的概念
经常有人把数据流比作水管,水管中的“水”就是要传输的数据。跟水管一样,数据流有一个特点:具有方向性。 以前面的场景为例子,输入流的方向是从键盘到程序,输出流、错误流的方向是从程序到屏幕。
根据百度百科的定义:数据流(data stream)是一组有序,有起点和终点的字节的数据序列。
Linux中的标准流
Linux中有三个标准流,在一个程序启动的时候它们会自动开启。它们分别是:
- 标准输入流(
stdin
: standard input,) - 标准输出流(
stdout
: standard output) - 标准错误流(
stderr
: standard error)
对应的文件描述符分别是:
- stdin:
0
- stdout:
1
- stderr:
2
程序运行的时候从输入流读取数据,作为程序的输入,程序运行过程中输出的信息被传送到输出流,类似的,错误信息被传送到错误流。
标准输入流
标准输入流默认是从键盘输入的信息。
例如,在Linux中,使用passwd
命令来修改密码:
pi@raspberrypi:~ $ passwd
为 pi 更改 STRESS 密码。
Current password:
新的 密码:
重新输入新的 密码:
passwd:已成功更新密码
在修改密码的过程中,你需要从键盘输入当前的密码和新的密码。标准输入流就是键盘,你输入的密码从标准输入流传送到passwd
程序。
除了键盘之外,标准输入流还可以是文件,或者其它程序的输出,后面会讲到。
标准输出流
输出流分为标准输出流和标准错误流,默认情况下,它们都会输出到屏幕。
以编译程序为例子,编译过程中的调试信息(标准输出流)和编译发生的错误(标准错误流)都会被显示在屏幕上。
标准输出流也可以被重定向到另外一个程序,或者一个文件。例如将当前目录中的文件列表写入到一个文件中:
ls > a.txt
默认情况下,ls
命令会输出当前目录中的文件和文件夹。不过这条命令运行后并没有任何输出,因为ls
命令的输出被重定向到文件a.txt
。如果查看a.txt
的文件内容,就会看到当前目录中的文件和文件夹列表。
标准错误流
与标准输出流类似,标准错误流默认也会输出到屏幕上。例如:
pi@raspberrypi:~ $ rm /
rm: 无法删除'/': 是一个目录
重定向
在Linux中,标准输入流默认来自键盘输入,标准输出流和标准错误流默认发送到屏幕。在必要的时候,可以对修改输入流的来源、修改输出流的目的,这就是重定向。
常用的重定向的符号:
>
: 将标准输出流重定向到文件(清空文件后写入)。>>
:将标准输出流重定向到文件(追加写入)。<
:将文件作为命令的标准输入流。
标准输出流重定向
# 以下命令执行后没有任何输出,因为输出流被重定向到文件,执行后可以在a.txt中查看ls的输出
ls > a.txt
# 将ls命令返回的结果追加写入到文件
ls >> a.txt
输入流重定向
# 将文件内容发送到远程主机(文件内容作为命令的输入流)
nc 192.168.1.1 80 < a.txt
# 更复杂的例子:将a.txt发送到远程主机,并将输出(远程主机返回的内容)写入到b.txt文件
nc 192.168.1.1 80 < a.txt > b.txt
错误流重定向
默认情况下,重定向符号>
和>>
只能对标准输出流进行重定向,而没有对标准错误流重定向。
例如,使用rm
命令删除根目录时,会报错无法删除:
pi@raspberrypi:~ $ rm /
rm: 无法删除'/': 是一个目录
尝试将输出写入到一个文件中:
pi@raspberrypi:~ $ rm / > b.txt
rm: 无法删除'/': 是一个目录
可以看到,错误信息依旧被显示到屏幕上,查看b.txt
时,发现什么内容都没有写入。
这是因为,重定向符号“>
”默认只会重定向标准输出流,而不会重定向标准错误流。所以标准错误流依旧按照默认方式输出到屏幕上。
如果想对错误流进行重定向,可以使用以下语法:
rm / 2> b.txt
即,在重定向符号前加上了一个2
,这个2
就是标准错误流的文件描述符。
命令执行后没有任何输出,在文件b.txt的内容中,可以看到:rm: 无法删除'/': 是一个目录
。
将标准输出流写入到output.txt,同时标准错误流写入到error.txt文件:
cat b.txt xxxxx.txt >output.txt 2>error.txt
将标准错误流重定向标准输出流,将标准输出流写入文件:
cat b.txt xxxxx.txt >output.txt 2>&1
上述命令中,2
表示标准错误流,1
表示标准输出流(加符&
的原因是,区分文件1
和标准输出流)。
管道符
管道符“|
”可以把一个程序的标准输出流作为另外一个程序的标准输入流,即前一个程序的输出作为后一个程序的输入。
在没有使用管道符的时候,获取可以登录shell的用户数量可以分为以下3步:
- 匹配
/etc/passwd
文件中包含“/bin/bash
”字符串(即可以登录shell的用户)的行,并写入到文件a.txt
中: - 用
wc -l a.txt
命令统计a.txt
文件中的行数。 - 删除
a.txt
文件。
命令如下:
pi@raspberrypi:~ $ grep "/bin/bash" /etc/passwd > a.txt
pi@raspberrypi:~ $ wc -l a.txt
3 a.txt
pi@raspberrypi:~ $ rm a.txt
如果使用管道符,只需要一行命令:
pi@raspberrypi:~ $ grep "/bin/bash" /etc/passwd | wc -l
3
首先,grep
读取/etc/passwd
文件,匹配并输出包含/bin/bash
的行,输出内容作为wc
命令的输入;
最后,wc -l
命令统计输入的行数,并最终输出到屏幕上。