当从命令行调用一个程序时,我可以通过pipe道输出到grep
来select我想要查看的行,例如
printf "hello\ngood day\nfarewell\n" | grep day
我在寻找相同types的行select,但是从Python调用的C库。 考虑下面的例子:
import os # Function which emulate a C library call def call_library(): os.system('printf "hello\ngood day\nfarewell\n"') # Pure Python stuff print('hello from Python') # C library stuff call_library()
当运行这个Python代码时,我希望C部分的输出在string'day'
被grep
,使得代码的输出
你好,来自Python
美好的一天
到目前为止,我已经使用这里和这里描述的方法来重新定位stdout
。 我可以使C输出完全消失,或者将其保存为str
,并在稍后打印出来(这是两个链接主要关心的部分)。 然而,我不能够根据其内容select打印哪一行。 重要的是,我希望在调用C库的同时实时输出,因此我不能只是将stdout
redirect到某个缓冲区,并在事后处理这个缓冲区。
该解决scheme只需要在Linux上使用Python 3.x。 如果除了行select之外 ,解决scheme使得行编辑成为可能,那将更大。
将stdout
redirect到内存中的“文件”。
产生一个不断从这个文件读取的新线程,根据行内容进行select,并将所需的行写入屏幕,即stdout
的原始目标。
调用C库
将两个线程重新join,并将stdout
redirect回原来的目标(屏幕)。
我没有足够的把握文件描述符等来做到这一点,甚至不知道这是否是最好的方法。
请注意,解决scheme不能简单地重新实现call_library
的代码。 代码必须调用call_library
,完全不call_library
实际的代码,然后执行。
我对你的程序到底在做什么感到困惑,但是听起来好像你有一个C 库写入到C stdout
( 不是 Python sys.stdout
),你想捕获这个输出并对其进行后处理,而你已经有一个C库的Python绑定,你宁愿使用它,而不是一个单独的C程序。
首先,你必须使用一个子进程来做到这一点; 没有别的将可靠地工作。 这是因为stdout
是全局进程的,所以没有可靠的方法来捕获只有一个线程的写入stdout
。
其次,你可以使用subprocess.Popen
,因为你可以使用它重新调用当前脚本! 这就是Python multiprocessing
模块所要做的事情,自己做起来并不难。 我会使用一个特殊的,隐藏的命令行参数来区分这个孩子,就像这样:
import argparse import subprocess import sys def subprocess_call_c_lib(): import c_lib c_lib.do_stuff() def invoke_c_lib(): proc = subprocess.Popen([sys.executable, __file__, "--internal-subprocess-call-c-lib" # , ... ], stdin=subprocess.DEVNULL, stdout=subprocess.PIPE) for line in proc.stdout: # filter output from the library here # to display to "screen", write to sys.stdout as usual if proc.wait(): raise subprocess.CalledProcessError(proc.returncode, "c_lib") def main(): ap = argparse.Parser(...) ap.add_argument("--internal-subprocess-call-c-lib", action="store_true", help=argparse.SUPPRESS) # ... more arguments ... args = ap.parse_args() if args.internal_subprocess_call_c_lib: subprocess_call_c_lib() sys.exit(0) # otherwise, proceed as before ... main()
如果grepping线打印到stderr,至少可以:
# Function which emulate a C library call def call_library(): os.system("echo hello") time.sleep(1.0) os.system("echo good day") time.sleep(1.0) os.system("echo farewell") time.sleep(1.0) os.system("echo done") class GrepThread(threading.Thread): def __init__(self, r,): threading.Thread.__init__(self) self.r = r def run(self): while True: s = self.r.readline() if not s: break if "day" in s: print(s, file=sys.stderr) original_stdout_fd = sys.stdout.fileno() # file descriptors r, w for reading and writing r, w = os.pipe() r = os.fdopen(r) os.dup2(w, original_stdout_fd) sys.stdout = io.TextIOWrapper(os.fdopen(original_stdout_fd, 'wb')) thread = GrepThread(r) thread.start() print("Starting", file=sys.stderr) call_library()
请注意,这不会关闭线程,也不会清理干净的东西,但似乎在我的电脑上工作。 它将在功能执行时打印行,而不是之后。