在linux系统上标准输入,标准输出,标准错误分别为stdin, stdout, stderr,对应着相应的文件描述符0, 1, 2。

用shell重定向:

# 标准输入
less < a.txt

# 标准输出
cat a.txt > b.txt
cat a.txt >> b.txt

# 标准错误到标准输出
someprogram 2>&1
someprogram > p.log 2>&1

# 管道
find . -iname "*.py" | grep encoding

在python中进行重定向也很简单

import sys
from subprocess import Popen, PIPE

# python2
print >>sys.stderr, "hello stderr"
# python3
print("hello stderr", file=sys.stderr)

p1 = Popen(["program", "arg1"], stdout=PIPE, stderr=PIPE)
f = open("p.log", "w")
p2 = Popen(["program", "arg1"], stdout=f, stderr=f)
p3 = Popen(["program_pipe"], stdin=p1.stdout)

每次输入输出的时候系统首先将字符读到缓冲区buffer内,然后再对buffer进行处理。在某些情况下我们需要手动flush缓存内容,比如以下情况时:

#include <stdio.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
    int a, b, c, d;
    char e;
    scanf("%d %d %d", &a, &b, &c);
    printf("%d %d %d", a, b, c);
    sleep(2);
    scanf("%c", &e);
    d = (int) e;
    printf("%d\n", d);

    return 0;
}

看一下上面的程序,逻辑很简单,输入三个整数,然后输出,睡眠2秒钟,输入一个字符,将字符转换为整数输出。实际运行就会发现一些问题。

第一个问题, 没有输入e的过程就运行结束了,给出的d的值为10. 这个因为我们输入前三个整数时输入的实际是"1 2 3\n",1 2 3被取走了,但是\n换行符还留在stdin的缓存内,所以它就直接赋给了e,\n对应的十进制为10,我们得到了10.显然这个不是我们要的结果。解决的办法是在前面输入后清空输入缓存,可以用fflush(stdin)或者while ((c = getchar()) != '\n' && c != EOF);

第二个问题, sleep之前的printf并没有将内容输出到屏幕上。这是由于linux系统默认是行缓存,就是只有输入换行符是才将buffer内容输出到屏幕上,对于这个我们可以在printf语句后加上fflush(stdout),这样虽然不是整行但是也会实时输出到屏幕,或者也可以在printf字符串中加上n,当然这样行为与之前的就不同了。

在python中同样也有输出缓存的问题

import sys
import time

for i in range(5):
    print "%d" % i,  # python3 version: print("%d" % i, end="", flush=True)
    sys.stdout.flush()  # 如果没有这一句,那所有内容在sleep(0.5 * 5)后才会一起输出
    time.sleep(0.5)
comments powered by Disqus