Wie kann ich Befehle an bestimmte Terminalfenster senden?

12


Ich möchte ein Skript schreiben, um mehrere Programme (Server) gleichzeitig in separaten Terminals zu öffnen - egal, welches - und verschiedene Befehle an verschiedene Terminals mit Befehlen "landen" innerhalb des richtigen Terminals zuweisen. Ist das möglich?
Vielleicht, etwas in der Art:

  1. Öffnen Sie terminal1
  2. öffne terminal2 // simultan mit 1.
  3. command1 // Ausführung in Terminal1, ohne ein neues Terminalfenster zu öffnen
  4. command2 // Ausführung in Terminal2, ohne ein neues Terminalfenster zu öffnen
  5. ...

Kann ich Terminalfenster irgendwie so beschriften, dass Befehle im richtigen Terminal ausgeführt werden?

Ich möchte auch alle Terminals beobachten, während ihre Programme laufen - meine Programme haben ein Argument für das Drucken von Trace / Debug auf Terminal. Also würde ich gerne sehen, welche Nachrichten zwischen ihnen ausgetauscht werden.

HINWEIS: Ich bin weniger besorgt über die Sicherheit der ausgetauschten Daten, da dieses Skript als "Simulation" dienen soll. Ich habe jeden Server so konfiguriert, dass er von einem zugewiesenen Port auf localhost ausgeführt wird.

    
Aliakbar Ahmadi 27.06.2015, 19:12
quelle

1 Antwort

13

Da Sie erwähnen, dass Sie das Problem für Ihre spezifische Situation gelöst haben, unter einer Lösung für allgemeine Zwecke. Dank xdotool 's --sync Option funktioniert es ziemlich zuverlässig in den Tests, die ich ausgeführt habe; Ich konnte Befehle an bestimmte Terminalfenster "senden" und es lief perfekt ohne Ausnahme.

Wie es in der Praxis funktioniert

Die Lösung besteht aus einem Skript, das mit zwei Optionen ausgeführt werden kann -set und -run :

  1. Um festzulegen öffnen (öffnen) Sie eine beliebige Anzahl von Terminalfenstern, in diesem Beispiel 3:

    target_term -set 3
    

    Drei neue Terminals werden geöffnet, ihre Fenster-ID wird in einer versteckten Datei gespeichert:

    Aus Gründen der Übersichtlichkeit habe ich das Terminalfenster minimiert, von dem ich den Befehl ausgeführt habe:)

  2. Nachdem ich nun drei Fenster erstellt habe, kann ich mit dem Befehl run (z. B.) Befehle an beide senden:

    target_term -run 2 echo "Monkey eats banana since it ran out of peanuts"
    

    Wie unten gezeigt, lief der Befehl im zweiten Terminal:

    Anschließend kann ich einen Befehl an das erste Terminal senden:

     target_term -run 1 sudo apt-get update
    

    macht sudo apt-get update in Terminal 1 laufen:

    und so weiter ...

So richten Sie

ein
  1. Das Skript benötigt sowohl wmctrl als auch xdotool :

    sudo apt-get install wmctrl xdotool
    
  2. Kopieren Sie das folgende Skript in eine leere Datei, sichern Sie es als target_term (keine Erweiterung!) in ~/bin (erstellen Sie bei Bedarf das Verzeichnis ~/bin .

  3. Machen Sie das Skript ausführbar (vergessen Sie nicht) und loggen Sie sich entweder aus oder führen Sie es aus:

    source ~/.profile
    
  4. Richten Sie nun Ihre Terminalfenster mit der Anzahl der erforderlichen Fenster als Argument ein:

    target_term -set <number_of_windows>
    
  5. Nun können Sie mit dem folgenden Befehl Befehle an eines Ihrer Terminals senden:

    target_term -run <terminal_number> <command_to_run>
    

Das Skript

#!/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)

Notizen

  • Das Skript ist auf gnome-terminal eingestellt, kann jedoch für jedes Terminal (oder anderes Programm) verwendet werden, indem% code_% im Kopfbereich des Skripts geändert wird:

    #--- set your terminal below
    application = "gnome-terminal"
    #---
    
  • Die obigen Befehle können (natürlich) auch von einem Skript aus ausgeführt werden, falls Sie es für eine Art Simulation verwenden möchten.
  • Das Skript wartet, bis das Zielfenster den Fokus hat und der Befehl fertig eingegeben ist, so dass der Befehl immer im rechten Terminalfenster landen wird.
  • Es muss nicht gesagt werden, dass das Skript nur mit dem Terminal-Setup (Windows) funktioniert, das mit dem Befehl aufgerufen wurde:

    target_term -set
    

    Die Terminalfenster werden dann vom Skript "beschriftet", wie Sie in Ihrer Frage angeben.

  • Wenn Sie eine neue application -Sitzung starten, wird die versteckte Datei, die vom Skript erstellt wurde, einfach überschrieben, so dass Sie sie nicht entfernen müssen.
Jacob Vlijm 28.06.2015, 22:38
quelle