Jak mogę wysyłać polecenia do określonych okien terminali?

13


Chciałbym napisać skrypt do jednoczesnego otwierania wielu programów (serwerów) w osobnych terminalach - nie ma znaczenia, który - i przypisywać różne polecenia do różnych terminali z poleceniami „lądującymi” wewnątrz właściwego terminala. czy to możliwe?
Może coś takiego:

  1. otwórz terminal 1
  2. otwórz terminal2 // jednocześnie z 1.
  3. polecenie1 // wykonaj w terminalu 1 bez otwierania nowego okna terminalu
  4. polecenie2 // wykonaj w terminalu 2 bez otwierania nowego okna terminalu
  5. ...

Czy mogę w jakiś sposób oznaczyć okna terminala, aby polecenia były wykonywane w odpowiednim terminalu?

Chciałbym również oglądać wszystkie terminale podczas działania ich programów - moje programy mają argument do drukowania śledzenia / debugowania na terminalu. Chciałbym więc zobaczyć, jakie wiadomości są między nimi wymieniane.

UWAGA: Jestem mniej zaniepokojony bezpieczeństwem wymienianych danych, ponieważ ten skrypt powinien służyć jako „symulacja”. Skonfigurowałem każdy serwer, aby działał z przydzielonego portu na localhost.

Aliakbar Ahmadi
źródło
Sprawdź pssh ....
heemayl
Jak dokładny powinien być czas; czy połączenie powiedzmy 2 sekundy (na terminal) jest właściwe?
Jacob Vlijm
@JacobVlijm: dla mnie ważniejsze jest prawidłowe przypisywanie poleceń do „okna” terminala
Aliakbar Ahmadi
1
Można to zrobić, zwłaszcza jeśli chodzi o symulację,
odeśle z
1
@JacomVlijm: właściwie moje pytanie zostało przypadkowo rozwiązane: aby wysłać polecenie do właściwej instancji, każde polecenie musi być poprzedzone datadirem, od którego zaczyna się instancja! Ale na szczęście jest to zaimplementowane w bitcoinach, ale pozostawiam pytanie bez odpowiedzi .. może ktoś wpadnie na bardziej ogólny pomysł na dowolny program !? :) Ale dziękuję!
Aliakbar Ahmadi

Odpowiedzi:

14

Ponieważ wspomniałeś, że rozwiązałeś problem w konkretnej sytuacji, poniżej rozwiązania ogólnego zastosowania. Dzięki xdotool„s --syncopcja działa całkiem niezawodny w testach wpadłem; Mogłem „wysyłać” polecenia do określonych okien terminali i działało idealnie bez wyjątku.

Jak to działa w praktyce

Rozwiązanie istnieje ze skryptu, który można uruchomić za pomocą dwóch opcji -seti -run:

  1. Aby skonfigurować (otworzyć) dowolną liczbę okien terminali, w tym przykładzie 3:

    target_term -set 3

    Otworzą się trzy nowe terminale, ich identyfikator okna zostanie zapamiętany w ukrytym pliku:

    wprowadź opis zdjęcia tutaj

    Dla jasności zminimalizowałem okno terminala, z którego uruchomiłem polecenie :)

  2. Teraz, gdy utworzyłem trzy okna, mogę wysyłać polecenia do jednego z nich za pomocą polecenia uruchamiania (np.):

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

    Jak pokazano poniżej, polecenie uruchomiono w drugim terminalu:

    wprowadź opis zdjęcia tutaj

    Następnie mogę wysłać polecenie do pierwszego terminala:

     target_term -run 1 sudo apt-get update

    podejmowania sudo apt-get updateuruchomić w terminalu 1:

    wprowadź opis zdjęcia tutaj

    i tak dalej...

Jak skonfigurować

  1. Skrypt potrzebuje zarówno wmctrla xdotool:

    sudo apt-get install wmctrl xdotool
  2. Skopiuj poniższy skrypt do pustego pliku, zabezpiecz go jako target_term(bez rozszerzenia!) W ~/bin(w ~/binrazie potrzeby utwórz katalog) .

  3. Ustaw skrypt jako wykonywalny (nie zapomnij) i wyloguj się / zaloguj lub uruchom:

    source ~/.profile
  4. Teraz skonfiguruj okna terminala, podając liczbę wymaganych okien jako argument:

    target_term -set <number_of_windows>
  5. Teraz możesz „wysłać” polecenia do jednego z terminali za pomocą polecenia:

    target_term -run <terminal_number> <command_to_run>

Scenariusz

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

Notatki

  • Skrypt jest ustawiony gnome-terminal, ale można go używać w dowolnym terminalu (lub innym programie), zmieniając applicationsekcję „head” skryptu:

    #--- set your terminal below
    application = "gnome-terminal"
    #---
  • Powyższe polecenia można (oczywiście) uruchomić również ze skryptu, na wypadek gdybyś chciał użyć go do jakiejś symulacji.
  • Skrypt czeka, aż oba okno docelowe zostanie zogniskowane, a polecenie zakończy pisanie, więc polecenie zawsze wyląduje w prawym oknie terminala.
  • Nie trzeba mówić, że skrypt działa tylko z konfiguracją terminala (Windows), która została wywołana przez polecenie:

    target_term -set

    Okna terminala zostaną wówczas „oznaczone” przez skrypt, tak jak wspomniałeś w swoim pytaniu.

  • W przypadku rozpoczęcia nowej target_termsesji ukryty plik utworzony przez skrypt zostanie po prostu nadpisany, więc nie ma potrzeby usuwania go w inny sposób.
Jacob Vlijm
źródło
Niezły, dzięki! Należy również zauważyć, że Python 3.x jest również wymagany do działania tego skryptu.
pompalini