为什么这个 bash 命令在我 运行 它通常在 shell 但通过 Python 的 Popen 失败时起作用?

Why does this bash command work when I run it normally in a shell but fail through Python's Popen?

我想用 python 在 Kali 中生成一个终端,然后发送操作终端 window。

所以我可以生成一个新终端并在 Python:

中获取它的 pid
from subprocess import Popen, PIPE, STDOUT, check_output
p1 = Popen(['x-terminal-emulator'])
print(f'pid: {p1.pid}') // 31700

然后将其传递给 xdotool,例如:

xdotool search --pid 31700

标准输出:

90177537 // first code given isn't the one to use
88080390 // second one seems to work, not sure why

然后将其传递回 xdotool:

xdotool windowfocus 88080390

成功!我可以移动 window,将其传递给输入等

但是当我尝试将所有这些组合到 Python 代码中时,xdotool search --pid 31700 命令失败:

from subprocess import Popen, PIPE, STDOUT, check_output
p1 = Popen(['x-terminal-emulator'])
print(f'pid: {p1.pid}')
window_id = check_output(['xdotool', 'search', '--pid', str(p1.pid)])

错误:

pid: 548
Traceback (most recent call last):
  File "/mnt/c/Users/jonat/Documents/Github/net-vis/python/scanner.py", line 6, in <module>
    window_id = check_output(['xdotool', 'search', '--pid', str(p1.pid)])
  File "/usr/lib/python3.9/subprocess.py", line 424, in check_output
    return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
  File "/usr/lib/python3.9/subprocess.py", line 528, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['xdotool', 'search', '--pid', '548']' returned non-zero exit status 1.

我做错了什么?

我认为您遇到了竞争条件。在 x-terminal-emulator 进程开始 运行 和它实际启动 window 并且可以使用 xdotool 发现之间有一个间隔。只需在您的代码中添加一个短暂的等待即可使它对我有用:

import subprocess
import time

p1 = subprocess.Popen(['x-terminal-emulator'])
print(f'pid: {p1.pid}')
time.sleep(2)
window_id = subprocess.check_output(['xdotool', 'search', '--pid', str(p1.pid)])

或者不用睡眠,而是使用轮询循环等待 xdotool 成功,可能有某种超时:

import subprocess
import time

p1 = subprocess.Popen(['lxterminal'])
print(f'pid: {p1.pid}')

t_start = time.time()
while True:
    try:
        window_id = subprocess.check_output(['xdotool', 'search', '--pid', str(p1.pid)])
        break
    except subprocess.CalledProcessError:
        t_delta = time.time() - t_start
        if t_delta > 5:
            raise
        time.sleep(0.1)

print('got window id:', window_id)

第二种解决方案会给您更好的响应时间。