Python 如果在 bash 中使用管道,则使用子进程和 xclip 的脚本会挂起

Python script using subprocess and xclip hangs if piped in bash

我有一个 python 脚本需要将一些值输出到标准输入并将另一个字符串复制到剪贴板。我正在使用模块 subprocess 通过 Popen 执行 xclip 实用程序,如下所示:

# clip.py
import subprocess
from subprocess import Popen

print('PRINT_ME')
p1 = Popen(['xclip', '-selection', 'clipboard'], stdin=subprocess.PIPE)
p1.communicate(input=('PASTE_ME'.encode()))

脚本按预期工作:PRINT_ME 在 bash 中回显并且 PASTE_ME 可以粘贴,returns 立即。

将脚本输出通过管道传输到另一个命令时出现问题。假设有人想使用 tee:

重定向到一个文件和标准输入
$ python clip.py|tee file.txt

该程序按预期工作,但不是 returns,即 shell 不要交还控制权。

如何解决这个问题?

一些重要信息xclip 实用程序 forks 本身(以应对 X 上剪贴板的实现)维护可以复制的字符串,当在 shell 中使用时,它会立即 returns (它分叉到后台)。 shell 似乎将 clip.pyxclip stdin/stdout 附加到 tee
如果使用 ps u 找到 xclip -selection clipboard 并终止命令 returns。

我正在使用 Python 3.4.
谢谢

这不是由于 xclip 的分叉,而是由于 Python 处理 Popen.wait() 的方式(通过调用 communicate() 调用)- 来自 Python perspective xclip(默认情况下为静音)没有关闭其流,因此它等待...这就是为什么一切正常,除了 Python 在管道其流时移过 p1.communicate() 行到别的东西(tee 在这种情况下) - 它等待它的所有文件句柄关闭...

您可以手动打开和关闭流,或者只配置 xclip 以将 STDIN 过滤为 STDOUT 并让 Python 满意:

import subprocess

p1 = subprocess.Popen(['xclip', '-selection', 'clipboard', '-f'], stdin=subprocess.PIPE)
p1.communicate(input=('PASTE_ME'.encode()))
# etc.

没有测试,但应该可以。如果您不希望 xclip 打印到您当前的 STDOUT,只需在将 subprocess.Popen() 实例化为 None(或 subprocess.DEVNULL 实例化 Python 3.x) 或您想要的任何其他流句柄。