Como posso enviar comandos para janelas de terminal específicas?

13


Eu gostaria de escrever um script para abrir vários programas (servidores) simultaneamente em terminais separados - não importa qual deles - e atribuir comandos diferentes a diferentes terminais com comandos "aterrissando" dentro do terminal correto. Isso é possível?
Talvez algo assim:

  1. terminal1 aberto
  2. abra terminal2 // simultaneamente com 1.
  3. command1 // executa no terminal1 sem abrir uma nova janela de terminal
  4. command2 // executa no terminal2 sem abrir uma nova janela de terminal
  5. ...

De alguma forma, posso rotular as janelas do terminal para que os comandos sejam executados dentro do terminal correto?

Eu também gostaria de assistir a todos os terminais enquanto seus programas estão em execução - meus programas têm um argumento para imprimir rastreio / depuração no terminal. Então, eu gostaria de ver quais mensagens são trocadas entre eles.

NOTA: Estou menos preocupado com a segurança dos dados trocados, pois esse script deve servir como uma "simulação". Eu configurei cada servidor para executar a partir de uma porta alocada no host local.

Aliakbar Ahmadi
fonte
Verifique pssh ....
heemayl
Quão preciso deve ser o tempo; é uma marge de digamos 2 segundos (por terminal) apropriado?
Jacob Vlijm
@JacobVlijm: é mais importante para mim comandos atribuir corretamente de acordo com terminal "janela"
Aliakbar Ahmadi
1
Pode ser feito, especialmente quando se trata de simulação, irá enviar de volta :)
Jacob Vlijm
1
@ JacomVlijm: na verdade, minha pergunta está resolvida incidentalmente: para enviar um comando para sua instância correta, cada comando deve ser prefixado com o datadir em que a instância começa! Mas, para minha sorte, isso é implementado no bitcoin, mas vou deixar a pergunta sem resposta .. talvez alguém tenha uma idéia mais geral para qualquer programa !? :) Mas obrigado!
Aliakbar Ahmadi

Respostas:

14

Como você mencionou, resolveu o problema para sua situação específica, abaixo de uma solução para uso geral. Graças ao xdotool's --syncopção, ele funciona muito confiável nos testes que fiz; Eu poderia "enviar" comandos para janelas de terminal específicas e funcionou perfeitamente sem uma exceção.

Como funciona na prática

A solução existe a partir de um script, que pode ser executado com duas opções -sete -run:

  1. Para configurar (abrir) um número arbitrário de janelas de terminal, neste exemplo 3:

    target_term -set 3

    Três novos terminais se abrirão, seu ID de janela será lembrado em um arquivo oculto:

    insira a descrição da imagem aqui

    Por motivos de clareza, minimizei a janela do terminal da qual executei o comando :)

  2. Agora que criei três janelas, posso enviar comandos para qualquer uma delas com o comando run (por exemplo):

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

    Como mostrado abaixo, o comando foi executado no segundo terminal:

    insira a descrição da imagem aqui

    Posteriormente, posso enviar um comando para o primeiro terminal:

     target_term -run 1 sudo apt-get update

    fazendo sudo apt-get updatecorrer no terminal 1:

    insira a descrição da imagem aqui

    e assim por diante...

Como configurar

  1. O script precisa de ambos wmctrle xdotool:

    sudo apt-get install wmctrl xdotool
  2. Copie o script abaixo em um arquivo vazio, proteja-o como target_term(sem extensão!) Em ~/bin(crie o diretório, ~/binse necessário.

  3. Torne o script executável (não se esqueça) e efetue logout / login ou execute:

    source ~/.profile
  4. Agora configure suas janelas de terminal, com o número de janelas necessárias como argumento:

    target_term -set <number_of_windows>
  5. Agora você pode "enviar" comandos para qualquer um dos seus terminais com o comando:

    target_term -run <terminal_number> <command_to_run>

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

Notas

  • O script está definido para gnome-terminal, mas pode ser usado para qualquer terminal (ou outro programa também), alterando a applicationseção head do script:

    #--- set your terminal below
    application = "gnome-terminal"
    #---
  • Os comandos acima podem (é claro) ser executados a partir de um script, caso você deseje usá-lo para algum tipo de simulação.
  • O script aguarda até que a janela de destino tenha foco e o comando seja digitado, para que o comando sempre apareça na janela do terminal direita.
  • Não é necessário dizer que o script funciona apenas com a configuração do terminal (windows) que foi chamada pelo comando:

    target_term -set

    As janelas do terminal serão "rotuladas" pelo script, como você mencionou na sua pergunta.

  • Caso você inicie uma nova target_termsessão, o arquivo oculto, criado pelo script, será simplesmente substituído, portanto, não será necessário removê-lo.
Jacob Vlijm
fonte
Nice, obrigado! Também deve ser observado que o python 3.x também é um requisito para esse script funcionar.
Pompalini 06/06/19