web-dev-qa-db-ja.com

特定の端末ウィンドウにコマンドを送信するにはどうすればよいですか?


複数のプログラム(サーバー)を別々の端末で同時に開くためのスクリプトを書きたい-どの端末でも構いません-正しい端末内に「着陸」するコマンドで異なる端末に異なるコマンドを割り当てます。 これは可能ですか?
たぶん、このようなもの:

  1. ターミナル1を開く
  2. terminal2 //同時に1を開きます。
  3. command1 //新しいターミナルウィンドウを開かずにterminal1で実行
  4. command2 //新しいターミナルウィンドウを開かずにterminal2で実行
  5. ...

コマンドが正しい端末内で実行されるように、何らかの方法で端末ウィンドウにラベル付けできますか?

また、プログラムの実行中にすべての端末を監視したい-私のプログラムには、端末にトレース/デバッグを出力するための引数があります。だから、私はそれらの間でどのようなメッセージが交換されているかを見たいです。

注:このスクリプトは「シミュレーション」として機能するため、交換データのセキュリティについてはあまり気にしません。 localhostの割り当てられたポートから実行するように各サーバーを構成しました。

13
Aliakbar Ahmadi

あなたがあなたの特定の状況の問題を解決したと述べたので、一般的な目的のための解決策の下に。 xdotool--syncオプションのおかげで、実行したテストでかなり信頼性の高い動作をします。特定のターミナルウィンドウにコマンドを「送信」でき、例外なく完全に実行されました。

実際の仕組み

ソリューションは、2つのオプション-setおよび-runで実行できるスクリプトから存在します。

  1. set up(開く)任意の数のターミナルウィンドウ、この例3:

    target_term -set 3
    

    3つの新しいターミナルが開き、それらのウィンドウIDは隠しファイルに記憶されます。

    enter image description here

    明確にするために、端末ウィンドウを最小化してからコマンドを実行しました:)

  2. 3つのウィンドウを作成したので、runコマンド(たとえば)を使用して、いずれかのウィンドウにコマンドを送信できます。

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

    以下に示すように、コマンドは2番目のターミナルで実行されました。

    enter image description here

    その後、最初の端末にコマンドを送信できます。

     target_term -run 1 Sudo apt-get update
    

    Sudo apt-get updateをターミナル1で実行する:

    enter image description here

    等々...

設定方法

  1. スクリプトには、wmctrlxdotoolの両方が必要です。

    Sudo apt-get install wmctrl xdotool
    
  2. 以下のスクリプトを空のファイルにコピーし、target_term(拡張子なし!)として~/bin(必要に応じてディレクトリ~/binを作成します)として安全にします。

  3. スクリプトexecutableを作成し(忘れないでください)、ログアウト/ログインするか、実行します:

    source ~/.profile
    
  4. 次に、必要なウィンドウの数を引数として、ターミナルウィンドウをセットアップします。

    target_term -set <number_of_windows>
    
  5. これで、コマンドを使用して端末のいずれかにコマンドを「送信」できます。

    target_term -run <terminal_number> <command_to_run>
    

スクリプト

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

ノート

  • スクリプトはgnome-terminalに設定されていますが、スクリプトのheadセクションのapplicationを変更することにより、任意の端末(または他のプログラム)に使用できます。

    #--- set your terminal below
    application = "gnome-terminal"
    #---
    
  • 上記のコマンドは、もちろん、何らかのシミュレーションに使用したい場合に備えて、スクリプトから実行することもできます。
  • スクリプトは、ターゲットウィンドウにフォーカスがあり、コマンドの入力が完了するまで待機するため、コマンドは常に正しいターミナルウィンドウに表示されます。
  • スクリプトは、コマンドによって呼び出されたターミナルセットアップ(ウィンドウ)でのみ機能することを言う必要はありません。

    target_term -set
    

    ターミナルウィンドウは、質問で言及したように、スクリプトによって「ラベル付け」されます。

  • 新しいtarget_termセッションを開始する場合、スクリプトによって作成された隠しファイルは単に上書きされるため、削除する必要はありません。
14
Jacob Vlijm