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

12


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

  1. aberto terminal1
  2. aberto 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. ...

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

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 o 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 em localhost.

    
por Aliakbar Ahmadi 27.06.2015 / 19:12

1 resposta

13

Desde que você mencionou, resolveu o problema para sua situação específica, abaixo de uma solução para propósitos gerais. Graças à opção xdotool do --sync , funciona bastante confiável nos testes que executei; Eu poderia "enviar" comandos para janelas de terminal específicas e ele funcionava perfeitamente sem uma exceção.

Como funciona na prática

A solução existe em um script, que pode ser executado com duas opções -set e -run :

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

    target_term -set 3
    

    Três novos terminais serão abertos, o ID da janela é lembrado em um arquivo oculto:

    Por motivos de clareza, eu minimizei a janela do terminal. Eu executei o comando de:)

  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:

    Posteriormente, posso enviar um comando para o primeiro terminal:

     target_term -run 1 sudo apt-get update
    

    fazendo com que sudo apt-get update seja executado no terminal 1:

    e assim por diante ...

Como configurar

  1. O script precisa dos dois wmctrl e xdotool :

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

  3. Torne o script executável (não esqueça) e efetue logout / in 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 o application na seçã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ê queira usá-lo para algum tipo de simulação.
  • O script aguarda até que a janela de destino tenha foco e o comando seja feito com digitação, para que o comando sempre caia na janela do terminal à direita.
  • Não há necessidade de dizer que o script só funciona com a configuração do terminal (windows) que foi chamada pelo comando:

    target_term -set
    

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

  • Caso você inicie uma nova sessão target_term , o arquivo oculto, criado pelo script, será simplesmente sobrescrito, portanto, não há necessidade de removê-lo de outra forma.
por Jacob Vlijm 28.06.2015 / 22:38