web-dev-qa-db-ja.com

ターミナルのブロック開始

この簡単なテストコマンドを入力すると:

gnome-terminal -x bash -c "ls;sleep 3"

すぐに戻ることがわかります(もちろん、新しく作成されたターミナルは3秒間残ります)。これは、たとえば、rxvt(同じコマンドですが、eを使用)とは対照的です。

ブロッキングの開始が必要な場合、歴史的なコンセンサスは --disable-factoryを使用する であったようです。残念ながら、これはもう機能しません(テスト済みの3.14.2)。

したがって、非同期ではない方法で端末を起動するにはどうすればよいですか?

ボーナス:konsolelxterminal、およびxfce4-terminalも少なくとも同じ問題を抱えています。それらのコマンド?

5
imallett

私は、terdonの答えといくつかの類似点がある(そして彼の助けを借りて作成された-ありがとう@ terdonこれは!)メソッドを使用しますが、アプローチが少し異なります:

一時ファイルを作成して、子端末が親端末と通信し、対応するbashインスタンスのPIDを通知できるようにします。次に、親端末に一時ファイルを読み取らせてPIDを記憶させ、ファイルを削除して、子端末のbashインスタンスがまだ実行されているかどうかを100ミリ秒ごとに確認します(遅延を変更できます)。そうでない場合、端末は手動で、またはコマンドが終了したために閉じられました。その後、起動コマンドが終了し、親端末が再び使用可能になります。

このアプローチの利点:
起動されるすべてのコマンド(ls; sleep 3またはそれらの代替)は、実行するafterを担当するコマンド端末のクローズの検出を許可します。そのため、内部コマンドがハングするか、端末が終了する前に手動で閉じた場合、メカニズムはまだ機能しており、無限ループに陥る代わりに外部スクリプトの実行を継続します。


デバッグ出力(子端末ウィンドウを開いた後に「起動」、閉じた後に「終了」)と0.1秒の精度を持つワンライナーとしてのコードは次のとおりです。

pidfile=$(mktemp); gnome-terminal -x bash -c "echo \$$>$pidfile; ls; sleep 3"; until [ -s $pidfile ]; do sleep 0.1; done; terminalpid=$(cat "$pidfile"); rm $pidfile; echo "launched"; while ps -p $terminalpid > /dev/null 2>&1; do sleep 0.1; done; echo "terminated"

またはデバッグ出力なし:

pidfile=$(mktemp); gnome-terminal -x bash -c "echo \$$>$pidfile; ls; sleep 3"; until [ -s $pidfile ]; do sleep 0.1; done; terminalpid=$(cat "$pidfile"); rm $pidfile; while ps -p $terminalpid > /dev/null 2>&1; do sleep 0.1; done

ほぼ同じコードですが、bashスクリプトとして記述された柔軟性があります。

#! /bin/bash

delay=0.1
pidfile=$(mktemp)

gnome-terminal -x bash -c "echo \$$>$pidfile; ls; sleep 3"

until [ -s $pidfile ] 
    do sleep $delay
done
terminalpid=$(cat "$pidfile")
rm $pidfile
echo "launched"
while ps -p $terminalpid > /dev/null 2>&1
    do sleep $delay
done
echo "terminated"

もちろんecho "launched"行とecho "terminated"行を省略できます。また、必要に応じてdelay=0.1行を、端末状態の2つのチェック(秒単位)間の別の遅延に変更できます。多かれ少なかれ正確に。

子端末で別のカスタムコマンドを実行するには、次の行を置き換えます

gnome-terminal -x bash -c "echo \$$>$pidfile; ls; sleep 3"

次のように(大文字のプレースホルダーの代わりにコマンドを挿入してください!)

gnome-terminal -x bash -c "echo \$$>$pidfile; INSERTYOURCOMMANDSHERE"
4
Byte Commander

無限の知恵で、GNOME開発者はそのオプションを削除することにしました。残念ながら、彼らの知恵は、まだリストされているmanページの更新にも及ばなかった。したがって、gnome-terminalは常にバックグラウンドで実行され、親のシェルセッションはすぐに返されるように見えます。これを回避するには、いくつかのオプションがあります。

  1. 別の端末を使用するだけです。 xterm、rxvt、およびGNOMEターミネーターを試してみましたが、すべて期待どおりに機能しました。

  2. Someいハックを使用します。 gnome-terminalは、最初の実行時に/usr/lib/gnome-terminal/gnome-terminal-serverを起動します。何らかの理由で、これはプロセスを起動するとすぐに終了することを意味します。説明する:

    $ gnome-terminal  -x sh -c "ls;sleep 30" 
    [1] 5896
    $ jobs
    [1]+  Done                    gnome-terminal -x sh -c "ls;sleep 30"
    

    上記でわかるように、バックグラウンドで起動した後、起動したジョブはすぐに終了します。つまり、最初にバックグラウンドで起動し、$!を使用してそれがまだ実行されているかどうかを確認することは最初は考えられません。これは、ファイルを作成するようなエレガントではない何かをする必要があることを意味します。

    tmpfile=$(mktemp); gnome-terminal  -x sh -c "ls;sleep 30; rm $tmpfile" 
    while [ -e $tmpfile ] ; do :; done
    

    上記のコマンドは、i)一時ファイル(tmpfile=$(mktemp))を作成します。 ii)gnome-terminalを起動し、完了したら$tmpfileを削除し、iii)一時ファイルが存在する限り何もしない(:while [ -e $tmpfile ]を指示します。これにより、端末はgnome-terminalによって実行されるプロセスが終了するまで待機してから続行します。

3
terdon

Gnome-terminalパッケージのUbuntuメンテナーはこの問題に気づき、gnome-terminal-3.14.2-0ubuntu3オプションを再度有効にするラッパースクリプト(Ubuntuパッケージ--disable-factory)を作成しました。ただし、ラッパースクリプトは機能しません。

変更ログから http://changelogs.ubuntu.com/changelogs/pool/main/g/gnome-terminal/gnome-terminal_3.14.2-0ubuntu3/changelog

gnome-terminal(3.14.2-0ubuntu3)鮮やか; urgency = medium

  • debian/gnome-terminal:ラッパースクリプトを追加して、ユーザーが現在無視されている--disable-factoryオプションを渡すと、異なるapp-idでgnome-terminalを起動します。これにより、アップグレードするユーザーの古いランチャーとの互換性が復元されます。 [...]

Ubuntu "Launchpad"をナビゲートすることはできません(オープンソースの場合)。ラッパースクリプトは https://launchpad.net/ubuntu/+archive/primary/+files/gnome-terminal_3にあります.14.2-0ubuntu3.debian.tar.xzgnome-terminal.wrapと呼ばれます)。

バグは、gnome-terminal.wrapスクリプトが間違った子プロセスを待機していることです。ターミナルクライアントではなく、ターミナルサーバーで待機する必要があります。修正方法は、次のように2つのメソッドserver_appearedおよびspawn_terminal_serverを変更することです。

    def server_appeared(self, con, name, owner):
        # start gnome-terminal now
        gt = Gio.Subprocess.new(['/usr/bin/gnome-terminal.real',
                                 '--app-id', name] +
                                self.args,
                                Gio.SubprocessFlags.NONE)
        # removed a line here: gt.wait_async(...)

    def spawn_terminal_server(self, name):
        ts = Gio.Subprocess.new(['/usr/lib/gnome-terminal/gnome-terminal-server',
                                 '--app-id',
                                 name],
                                Gio.SubprocessFlags.NONE)
        ts.wait_async(None, self.exit_loop, ts)

修正済みファイルは、次の場所からダウンロードできます。 https://Gist.github.com/ecatmur/00893506a23e828c6688

私はパッケージメンテナーに通知しましたので、うまくいけばそれはかなりすぐに修正されるべきです。


別の興味深い事実:gnome-terminalは、gterminalと呼ばれる代替クライアントを使用して構築できます。このクライアントには、希望どおりの動作をする--waitオプションがあります。ただし、残念ながらUbuntuはgnome-terminalパッケージにビルドまたはインストールしません。

3
ecatmur

Google経由でこのサイトにアクセスした2017年2月<t <2018年3月の人々にとって、簡単な解決策は次のとおりです。

gnome-terminal --disable-factory -e "cmd"

gnome-terminalが動作し、期待どおりに同期/ブロック方式で起動します。

以下でテスト:

  • Ubuntu 16.04
  • gnome-terminal 3.18.3
0
Oscillon

私は新しいgnome-terminalを使用していますが、gnome-terminalについて説明した動作は、konsole、lxterm、およびrxvtで同じように見えます(3つすべてを試しました)。そのため、OPはこれまでのところ何を望んでいるかを明確にするためのコメントに答えていないので、OPは子端末の終了を待たずに親端末を使い続けたいと考えています。

それはgnome-terminal &で実現できます。親が終了するときに子端末が閉じられないようにするには、Nohup gnome-terminal &を使用します。親端末でエラー出力が表示されないようにするには、gnome-terminal 2> /dev/null &またはNohup gnome-terminal 2> /dev/null &を使用します。

0