0

通常这不是什么大问题,因为通过 STDIN/STDOUT 传递数据很简单。

但我正在开发一个 diff 工具,它有两个输入和一个输出。

考虑:

diff <(curl 'http://google.com') <(curl 'https://google.com')
5c5
< <A HREF="http://www.google.com/">here</A>.
---
> <A HREF="https://www.google.com/">here</A>.

现在这对于一个普通的旧 python 程序来说很好,因为我可以open(sys.argv[1], 'r').read()为 argv[1] 和 argv[2] 获取数据。

问题是我的区别是 google_diff_match_patch 的 C++ 实现,为了简单起见,我调用了该程序(它argv使用wifstreamwstring和读取它的 s getline)。

所以现在必须发生的事情是我必须“给” my/dev/fd/11给 my subprocess.Popen(['dmp']),除非我似乎无法将路径(通常是)/dev/fd/11/dev/fd/12in 作为dmpC++ 程序的 args 填充,因为它/dev/fd/11不是我的python 程序的/dev/fd/11.

为了进一步混淆这个问题,我必须在将文件发送给孩子之前读出文件的内容,因为我使用file的是“二进制文件”oracle:

file_process = Popen(['file', '-'], stdin=PIPE, stdout=PIPE)
file_content = open(filename, 'r').read()
(filetype, err) = file_process.communicate(file_content)
if filetype.find('text') == -1:
    # Popen my c++ program and try to feed it file_content

请不要给出“写入文件”之类的答案。我想实现这些输入重定向fifo,这样我就可以像使用任何其他命令行差异一样有效地使用该程序(例如,这包括curl在不保存到文件的情况下从网上获取某些内容)。

编辑:根据subprocess孩子应该继承文件描述符,如果close_fds参数是False的默认值。好的,所以这似乎表明如果在我的 python 包装程序中我调用open('/dev/fd/11')并且不关闭它,然后使用 fork 一个孩子Popen(),那个孩子应该能够以某种方式读取文件描述符 11。

好的,那么现在我有了 python 文件描述符 11 的内容,我该如何设置一个文件供孩子阅读?例如,如何复制 shell 的功能<(echo file contents)(不使用shell=Trueand echo,我知道我现在应该这样做)

4

1 回答 1

1

在我看来,你有一个外部可执行文件,它期望文件名作为参数,而你想从你的 Python 脚本中传递打开的文件描述符,对吗?这些文件描述符可能不是实际的文件,它们可能是stdin或其他管道?

如果是这种情况,您将不会有一份轻松的工作 - 应用程序需要文件名,而不是打开的文件。由于该可执行文件的代码按名称打开文件,因此您无法从 Python 脚本更改该行为 - 即使可执行文件继承了文件描述符,其代码也需要在编写时考虑到该假设。并不是该可执行文件中的代码无法执行您的建议,只是它不是为执行此操作而编写的。因此,您尝试做的是一种解决方法,不一定有一个干净的选择。

您说您不想要涉及写入文件的解决方案,但我觉得我应该指出,如果您的工作量很小,那确实是最简单的选择。如果您担心写入磁盘,那么您可以创建一个tmpfs分区或其他东西,但这变得相当繁琐(而且不是很便携)。

下一个最简单的甚至可能是编写一个直接调用 Google 库而不是使用第三方可执行文件的 C 扩展 - 我会说这比乱搞/proc/self/fd或任何东西要干净得多(也更便携)。事实上,刚刚检查了它已经提供了 Python API 的项目,那么你有理由不直接调用它吗?就个人而言,这绝对是我将采取的方法。

编辑: 啊,我刚刚发现 Python API 是纯 Python,而不是 C++ 模块的包装器,所以我猜你可能出于性能原因没有使用它。除非您有严格的性能要求,否则我仍然认为这是最简单的选择,但如果您真的需要 C++ 性能,那么您仍然可以选择编写自己的包装器。

如果您真的打算调用可执行文件并且不写入中间文件,那么我想您可以使用这些/dev/fd/*文件,但这可能只适用于真实文件。至少在 Linux 上,这些文件作为文件系统上底层文件的符号链接,因此如果您的可执行文件通过符号链接重新打开它们,它应该在每个文件的开头获得一个读取指针,并且能够正确执行差异。

但是,在 的情况下stdin,您处理的是管道而不是真实文件,所以我不相信这个技巧会奏效。如果您尝试一下,您将打开两个具有相同底层管道的进程以供读取。这意味着管道的任何输出都将到达一个随机的子进程(不是完全随机的,但从您的角度来看是不可预测的)。现在,只要您的进程没有stdin从那时开始读取,您就可以侥幸逃脱,但这是一件非常可疑的事情。

简而言之,您可能只需打开/proc/self/fd文件(或者/dev/fd如果您愿意)就可以逃脱,但这不是我推荐的。如果您使用的可执行文件没有以您想要的方式调用库,我建议直接调用该库,或者编写您自己的 Python C 扩展包装器,或者使用已经可用的 Python API。

于 2013-07-01T12:04:31.577 回答