How can I send commands to specific terminal windows?
I'd like to write a script for opening multiple programs (servers) simultanously in separate terminals - doesn't matter which one - and assign different commands to different terminals with commands "landing" inside the correct terminal. Is this possible?
Maybe, something like this:
- open terminal1
- open terminal2 //simultanously with 1.
- command1 //execute in terminal1 without opening a new terminal window
- command2 //execute in terminal2 without opening a new terminal window
- ...
Can I somehow label terminal windows so commands are executed inside correct terminal?
I'd also like to watch all terminals while their programs are running - my programs have an argument for printing trace/debug to terminal. So I'd like to see what messages are exchanged between them.
NOTE: I'm less concerned about security of exchanged data since this script should serve as a "simulation". I've configured each server to run from an allocated port on localhost.
Since you mention you solved the problem for your specific situation, below a solution for general purpose. Thanks to xdotool
's --sync
option, it works pretty reliable in the tests I ran; I could "send" commands to specific terminal windows and it ran perfectly without an exception.
How it works in practice
The solution exists from a script, which can be run with two options
-set
and -run
:
-
To set up (open) an arbitrary number of terminal windows, in this example 3:
target_term -set 3
Three new terminals will open up, their window id is remembered in a hidden file:
For clarity reasons I minimized the terminal window I ran the command from :)
-
Now that I created three windows, I can send commands to either one of them with the run command (e.g.):
target_term -run 2 echo "Monkey eats banana since it ran out of peanuts"
As shown below, the command ran in the second terminal:
Subsequently, I can send a command to the first terminal:
target_term -run 1 sudo apt-get update
making
sudo apt-get update
run in terminal 1:and so on...
How to set up
-
The script needs both
wmctrl
andxdotool
:sudo apt-get install wmctrl xdotool
Copy the script below into an empty file, safe it as
target_term
(no extension!) in~/bin
(create the directory~/bin
if necessary.-
Make the script executable (don't forget) and either log out/in or run:
source ~/.profile
-
Now setup your terminal windows, with the number of required windows as an argument:
target_term -set <number_of_windows>
-
Now you can "send" commands to either one of your terminals with the command:
target_term -run <terminal_number> <command_to_run>
The script
#!/usr/bin/env python3
import subprocess
import os
import sys
import time
#--- set your terminal below
application = "gnome-terminal"
#---
option = sys.argv[1]
data = os.environ["HOME"]+"/.term_list"
def current_windows():
w_list = subprocess.check_output(["wmctrl", "-lp"]).decode("utf-8")
w_lines = [l for l in w_list.splitlines()]
try:
pid = subprocess.check_output(["pgrep", application]).decode("utf-8").strip()
return [l for l in w_lines if str(pid) in l]
except subprocess.CalledProcessError:
return []
def arr_windows(n):
w_count1 = current_windows()
for requested in range(n):
subprocess.Popen([application])
called = []
while len(called) < n:
time.sleep(1)
w_count2 = current_windows()
add = [w for w in w_count2 if not w in w_count1]
[called.append(w.split()[0]) for w in add if not w in called]
w_count1 = w_count2
return called
def run_intterm(w, command):
subprocess.call(["xdotool", "windowfocus", "--sync", w])
subprocess.call(["xdotool", "type", command+"\n"])
if option == "-set":
open(data, "w").write("")
n = int(sys.argv[2])
new = arr_windows(n)
for w in new:
open(data, "a").write(w+"\n")
elif option == "-run":
t_term = open(data).read().splitlines()[int(sys.argv[2])-1]
command = (" ").join(sys.argv[3:])
run_intterm(t_term, command)
Notes
-
The script is set for
gnome-terminal
, but can be used for any terminal (or other program as well) by changing theapplication
in the head section of the script:#--- set your terminal below application = "gnome-terminal" #---
- The commands above can (of course) be run from a script as well in case you'd lile to use it for some kind of a simulation.
- The script waits until both the targeted window has focus and the command is done typing, so the command will always land in the right terminal window.
-
No need to say that the script only works with the terminal setup (windows) that was called by the command:
target_term -set
The terminal windows will then be "labelled" by the script, like you mention in your question.
- In case you start a new
target_term
session, the hidden file, created by the script will simply be overwritten, so there is no need to remove it otherwise.