Home > Back-end >  Why does this bash command work when I run it normally in a shell but fail through Python's Pop
Why does this bash command work when I run it normally in a shell but fail through Python's Pop

Time:09-25

I want to spawn a terminal in Kali with python, then send manipulate the terminal window.

So I can spawn a new terminal and get its pid in Python:

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

then pass it to xdotool like:

xdotool search --pid 31700

stdout:

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

and then pass that back to xdotool:

xdotool windowfocus 88080390

success! I can move the window around, pass it input, etc.

But when I try to combine all this into the Python code, the xdotool search --pid 31700 command fails:

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)])

error:

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.

What am I doing wrong?

CodePudding user response:

I think you've got a race condition. There's an interval between when the x-terminal-emulator process starts running and when it actually brings up a window and is discoverable using xdotool. Simply adding a short wait in your code makes it work for me:

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)])

Or instead of a sleep, use a polling loop to wait until xdotool is successful, possibly with some sort of timeout:

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)

The second solution will give you much better response time.

  • Related