sys.stdout.write()在Python中使用管道在错误的时间打印

时间:2017-01-28 18:29:20

标签: python stdout pipeline

我在与使用sys.stdout.write()函数打印相关的家庭作业中遇到问题。我要做的是实现一个支持stdin / stdout重定向和管道的简单shell。在下面的代码中,从我的程序" ch.py​​",问题是" %%"当输入的表达式包含管道时,要求输入似乎在错误的时间打印。

例如,如果我输入"找到-name ch.py​​ | xargs grep import",我想得到的是:

%% find -name ch.py | xargs grep import
import os
import sys
import shlex
%% 

但实际上我得到的是:

%% find -name ch.py | xargs grep import
%% import os
import sys
import shlex

由于当输入不包含管道时问题不存在,因为" ls"或者" cat ch.py​​",我想我的主进程在继续之前不会等待所有子进程完成。我试着调用" os.waitpid()"与其他组合的参数或使用" os.wait()"相反,似乎没有什么能解决这个问题。

有人可以帮助我理解我错了吗?

import os
import sys
import shlex


def main():
    while True:
        sys.stdout.write("%% ")
        sys.stdout.flush()

        user_input = sys.stdin.readline()

        if user_input:
            parsed_input, to_write = parse(user_input)
        else:  # user pressed Ctrl+D, exit program
            sys.stdout.write("Bye!\n")
            sys.exit(0)

        pid = os.fork()
        if pid == 0:  # EVALUATION PROCESS
            if to_write:              # if stdout redirection
                os.dup2(to_write, 1)  # write in file instead of stdout
                os.close(to_write)

            evaluate(parsed_input, len(parsed_input)-1)
        elif pid > 0:  # MAIN PROCESS
            os.waitpid(pid, 0)  # wait for evaluation to complete


def evaluate(parsed_input, pipe_count):
    if pipe_count == 0:
        # execute leftmost command of the expression
        os.execvp(parsed_input[0][0], parsed_input[0])
    elif pipe_count > 0:
        r, w = os.pipe()

        pid = os.fork()
        if pid == 0:  # CHILD
            os.close(w)
            os.dup2(r, 0)  # read from pipeline instead of stdin
            os.close(r)
            # execute right side of the pipeline
            os.execvp(parsed_input[-1][0], parsed_input[-1])
        elif pid > 0:  # PARENT
            os.close(r)
            os.dup2(w, 1)  # write in pipeline instead of stdout
            os.close(w)
            # evaluate left side of the pipeline
            evaluate(parsed_input[:-1], pipe_count-1)

1 个答案:

答案 0 :(得分:0)

这里是固定代码,再次感谢Sami Laine。

def evaluate(parsed_input, pipe_count):
    if pipe_count == 0:
        # execute leftmost command of the expression
        os.execvp(parsed_input[0][0], parsed_input[0])
    elif pipe_count > 0:
        r, w = os.pipe()

        pid = os.fork()
        if pid == 0:  # CHILD
            os.close(r)
            os.dup2(w, 1)  # write in pipeline instead of stdout
            os.close(w)
            # evaluate left side of the pipeline
            evaluate(parsed_input[:-1], pipe_count-1)
        elif pid > 0:  # PARENT
            os.close(w)
            os.dup2(r, 0)  # read from pipeline instead of stdin
            os.close(r)
            os.waitpid(pid, 0)  # wait for children to complete
            # execute right side of the pipeline
            os.execvp(parsed_input[-1][0], parsed_input[-1])