Wie kann ich Befehle an bestimmte Terminalfenster senden?

13


Ich möchte ein Skript zum gleichzeitigen Öffnen mehrerer Programme (Server) in getrennten Terminals schreiben - egal welches - und verschiedenen Terminals unterschiedliche Befehle zuweisen, wobei die Befehle im richtigen Terminal "landen". Ist das möglich?
Vielleicht so etwas:

  1. Terminal1 öffnen
  2. terminal2 öffnen // gleichzeitig mit 1.
  3. befehl1 // in terminal1 ausführen, ohne ein neues terminalfenster zu öffnen
  4. befehl2 // in terminal2 ausführen ohne ein neues terminalfenster zu öffnen
  5. ...

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

Ich möchte auch alle Terminals beobachten, während deren Programme ausgeführt werden - meine Programme haben ein Argument zum Drucken von Trace / Debug auf Terminal. Ich würde also gerne sehen, welche Nachrichten zwischen ihnen ausgetauscht werden.

HINWEIS: Ich mache mir weniger Sorgen um 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
quelle
Check pssh ....
heemayl
Wie genau sollte das Timing sein? Ist eine Zeitspanne von beispielsweise 2 Sekunden (pro Terminal) angemessen?
Jacob Vlijm,
@JacobVlijm: Es ist mir wichtiger, Befehle dem entsprechenden Terminal "Fenster"
zuzuweisen
1
Kann getan werden, vor allem, wenn es um Simulation geht, wird zurück :)
Jacob Vlijm
1
@JacomVlijm: eigentlich ist meine frage zufällig gelöst: um einen befehl an die richtige instanz zu senden, muss jedem befehl das datadir vorangestellt werden, mit dem die instanz beginnt! Aber zu meinem Glück ist dies in Bitcoin implementiert, aber ich lasse die Frage einfach unbeantwortet. Vielleicht hat jemand eine allgemeinere Idee für ein Programm !? :) Aber danke!
Aliakbar Ahmadi

Antworten:

14

Da Sie erwähnt haben, haben Sie das Problem für Ihre spezifische Situation gelöst, nachfolgend eine Lösung für allgemeine Zwecke. Dank xdotool‚s --syncOption, es funktioniert ziemlich zuverlässig in den Tests , die ich lief; Ich konnte Befehle an bestimmte Terminalfenster "senden" und es lief ohne Ausnahme einwandfrei.

Wie es in der Praxis funktioniert

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

  1. So richten Sie eine beliebige Anzahl von Terminalfenstern ein (öffnen Sie diese):

    target_term -set 3

    Es werden drei neue Terminals geöffnet, deren Fenster-ID in einer versteckten Datei gespeichert wird:

    Bildbeschreibung hier eingeben

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

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

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

    Wie unten gezeigt, wurde der Befehl im zweiten Terminal ausgeführt:

    Bildbeschreibung hier eingeben

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

     target_term -run 1 sudo apt-get update

    MAKING sudo apt-get updateim Terminal 1 auszuführen:

    Bildbeschreibung hier eingeben

    und so weiter...

Wie stellt man das ein

  1. Das Skript benötigt beides wmctrlund xdotool:

    sudo apt-get install wmctrl xdotool
  2. Kopieren Sie das Skript unten in eine leere Datei, speichern Sie es als target_term(keine Erweiterung!) In ~/bin(erstellen Sie das Verzeichnis, ~/binfalls erforderlich.

  3. Machen Sie das Skript ausführbar (nicht vergessen) und melden Sie sich entweder ab oder führen Sie Folgendes 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. Jetzt können Sie Befehle mit dem folgenden Befehl an eines Ihrer Terminals "senden":

    target_term -run <terminal_number> <command_to_run>

Das Drehbuch

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

Anmerkungen

  • Das Skript ist für festgelegt gnome-terminal, kann jedoch für jedes Terminal (oder auch für ein anderes Programm) verwendet werden, indem Sie Folgendes applicationim head-Abschnitt des Skripts ändern :

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

    target_term -set

    Die Terminalfenster werden dann vom Skript "beschriftet", wie Sie in Ihrer Frage erwähnt haben.

  • Wenn Sie eine neue target_termSitzung starten , wird die versteckte Datei, die vom Skript erstellt wurde, einfach überschrieben, sodass Sie sie ansonsten nicht entfernen müssen.
Jacob Vlijm
quelle
Schön, danke! Es sollte auch beachtet werden, dass Python 3.x auch eine Voraussetzung für das Funktionieren dieses Skripts ist.
Pompalini