跳转至

重定向和管道

stdin/stdout/stderr 与 重定向


点击这里,看视频讲解,学习下面内容

什么是终端设备

人在操作电脑时,其实是和 运行着的程序(术语称之为:进程) 在打交道(术语称之为:交互)。

进程 是 看不见 摸不着的,它们是 在 电脑CPU中执行的代码指令。

所以,我们 和 进程 交互的时候,必须有个设备,我们才能通过它 输入信息给进程,并且显示进程输出信息。

在上世纪六七十年代,计算机网络还没有出现, 计算机都是大型机器,非常的昂贵。 通常只有大公司和研究机构才有。

那时人们通过终端设备和计算机上的程序进行交互,见下图。

image

注意,终端设备 只有 显示器 和键盘 , 是没有 主机部分的。它和主机之间有根信号线,传递用户通过键盘输入的信息给程序,并显示程序输出的信息。


这样的终端设备,显然不能离主机太远。

人们需要在家、甚至在另外一个城市 操作远程主机,就不能使用这样的终端。

后来有了计算机网络,有了微型个人电脑,我们可以使用个人电脑,运行软件模拟终端设备,比如 putty,进行远程登录主机,访问主机上的进程。

我们在模拟终端程序putty中输入信息,查看putty程序窗口输出的内容。

这种 模拟终端的软件,对Linux来说,也是终端设备。



点击这里,看视频讲解,学习下面内容

Linux进程在启动后,通常就会打开3个文件句柄,标准输入文件(stdin),标准输出文件(stdout)和 标准错误文件(stderr)。

Linux进程,要从用户那里读入输入的信息,就是从stdin文件里面读取信息,要 输出 信息 给用户看 都是 输出到 stdout, 要 输出 错误提示 给用户看 都是 输出到 stderr。

而缺省情况下这三个文件stdin、stdout、stderr 都指向 —— 终端设备。

也就是说:

Linux进程从stdin里面读取信息其实就是从终端设备(比如终端模拟程序Putty)读取信息;

Linux进程写入信息到stdout或者stderr,其实就是打印到终端设备上。

如下图所示

image

比如,运行下面的Python程序,要读入信息,就是从终端读入,因为stdin指向终端设备

input("please input info:")

再比如:下面的命令echo输出给用户看的,就是输入到终端上,因为stdout指向终端设备

[root@bogon ~]# echo "hello byhy"
hello byhy


Stdout、Stderr重定向


点击这里,看视频讲解,学习下面内容

如果我们在Shell中输入命令的时候,使用 > 符号, 就可以将输入信息输出到其他文件(包括设备文件)中去。比如

ps > out

运行后,我们会发现out文件里面出现了ps的输入信息,而Putty终端窗口里面则没有任何内容打印出来了。

这个 > 就是 stdout 重定向符号, 它表示 stdout 不是指向 终端设备了,而是 重定向到 out 文件。 所以stdout 指向了 out 文件, 输入的信息就到 out 文件了。 终端屏幕上就没有信息了。

这时对应的示意图如下

image


而Stderr的重定向符号 是 2> 。 注意 2 和 > 之间不能有空格。

比如我们执行下面的命令,其中hhhh是个不存在的文件

ps hhhh 2> err 

我们就会发现putty屏幕上没有任何信息,而文件 err里面则有。


如果我们要,同时重定向stdout和stderr到同一个文件both中,命令写法如下:

command &> both


如果我们要,重定向stdout到out文件,并重定向stderr到err文件,命令写法如下:

command > out 2>err

您需要高效学习,找工作? 点击咨询 报名实战班

点击查看学员就业情况

stdin重定向


点击这里,看视频讲解,学习下面内容

我们也可以在命令中,将 标准输入stdin 重定向,使用符号 <

用 vi 创建一个 Python 2 代码文件 add.py ,其内容如下

for i in xrange(3):
    data=raw_input()
    print ('%s+1=%s' % (data,int(data)+1))

该程序从stdin 读取一个数字后,显示其加1后的结果。

再创建一个文件 add.dat内容如下(注意3后面有个空行)

1
2
3

执行如下命令

[byhy@localhost ~]$ python add.py < add.dat
1+1=2
2+1=3
3+1=4

看到了吗?不需要我们从终端输入数字,该程序直接从文件 add.dat中读取数据并执行操作了。

这个 < 就是 stdin 重定向符号, 它表示 stdin 不是指向 终端设备了,而是 重定向到 add.dat 文件。 所以 stdin 指向了 add.dat 文件, 程序就从add.dat 文件读入信息 了。

这时该进程对应示意图如下:

image


管道


点击这里,看视频讲解,学习下面内容

上面我们曾经学习过grep命令,这个命令可以从文件中过滤出 包含指定字符串模式 的行。

比如我们有个文件file1,里面有的行包含了mike 这个词。如果我们想把所有包含mike的行都找出来。 可以执行命令 grep mike file1

当grep命令中没有文件参数的时候比如 grep mike, 它就会等待我们在标准输入(一般是putty终端设备)中输入一行行的内容,进行实时的过滤


在Linux操作过程中,我们经常需要 将一个命令的输出的内容,给另一个命令作为输入的内容 进行处理。

比如,我们想查出进程号是 6536 的进程的信息。

我们用ps -ef 可以显示出所有的进程信息,但是这里面的内容太多了,我想过滤出其中包含 6536 字符串的行。

当然可以 用重定向符号 ps –ef > info.txt , 然后再使用grep从 info.txt中过滤 grep 6536 info.txt

但是这样比较麻烦,我们可以使用 管道操作符

我们看 这个命令 ps –ef | grep 6536

注意其中的 竖线 | , 这个就是管道操作符,它起的作用就是

● 将 前面的 ps –ef 命令的stdout(本来是输出到终端设备的) 重定向到一个 临时管道设备里面,

● 同时 将后一个命令 grep 6536 的stdin重定向到这个临时的管道设备。

那么这时会发生什么事情呢?ps –ef 命令的结果直接被 命令 grep 6536 过滤出来了。

这个过程可以用如下示意图表示

image


作业和练习

请使用 root 账号登录 Linux,依次执行下面的操作

  • 打印系统中所有进程名 为python 的进程信息 到 文件 ps.txt中

  • 用python编写一个程序longrun.py。 思考一个Linux命令,来运行 这个程序。

这个命令 能够 将该进程输出信息,导入到out.log文件,输出错误信息导入到err.log文件,并且保证关闭了远程终端,该进程也不会停止。

注意现在CentOS里面的Python是 2.7版本,打印语句和Python 3 不一样。应该这样写

import sys
print 'delayed output'
sys.stdout.flush() 

最后一行确保print 的缓冲刷新到文件,否则cat可能不能及时看到。