フロントエンド端末アクセスを介してバックグラウンドでコマンドを実行する

フロントエンド端末アクセスを介してバックグラウンドでコマンドを実行する

任意のコマンドを実行し、子プロセスと対話(具体的な詳細は省略)してから、終了するのを待つことができる関数を作成しようとしています。成功すると、入力はrun <command>まるで裸のように動作します<command>

子プロセスと対話しなかった場合は、単に次のように書いたことでしょう。

run() {
    "$@"
}

ただし、実行中に対話する必要があるため、coprocおよびを使用してより複雑な設定を使用しますwait

run() {
    exec {in}<&0 {out}>&1 {err}>&2
    { coproc "$@" 0<&$in 1>&$out 2>&$err; } 2>/dev/null
    exec {in}<&- {out}>&- {err}>&-

    # while child running:
    #     status/signal/exchange data with child process

    wait
}

(これは単純化されています。すべてのcoprocリダイレクトが実際に役に立つ作業を実行するわけではありませんが、"$@" &実際のプログラムではリダイレクトが必要です。)

コマンドは"$@"何でも構いません。私の機能は、run lsなどrun makeで動作しますがrun vim。 Vimがバックグラウンドプロセスであり、端末アクセス権がないことを検出して編集ウィンドウを表示するのではなく、それ自体が停止するため、失敗したようです。 Vimが正しく動作するように修正したいと思います。

coproc "$@"親シェルが「バックグラウンド」になっている間に「フォアグラウンド」で実行されるようにするにはどうすればよいですか?「子供との対話」部分は端末で読み書きすることはないので、フォアグラウンドで実行する必要はありません。 ttyの制御権をコルーチンに渡してくれて嬉しいです。

run()私がやっていることでは、親プロセスと"$@"子プロセスにあることが重要です。私はこの役割を変えることはできません。しかし、私はできる前景と背景を変更します。 (ただ何をすべきかわからない。)

私はVim固有のソリューションを探しているわけではありません。私はpseudo-ttyを避けることを好みます。私の理想的な解決策は、stdinとstdoutがtty、パイプに接続されている、またはファイルからリダイレクトされたときに同じようにうまく機能します。

run echo foo                               # should print "foo"
echo foo | run sed 's/foo/bar/' | cat      # should print "bar"
run vim                                    # should open vim normally

なぜコプロセスを使用するのですか?

私はcoprocなしでこの問題を書くことができます。

run() { "$@" & wait; }

私はちょうど同じ行動を使用しました&。しかし、私のユースケースではFIFO coproc設定を使用していますcmd &coproc cmd

なぜptysを避けるべきですか?

run()自動化された環境で使用できます。パイプやリダイレクトに使用されている場合はエミュレートする端末がなく、ptyを設定するとエラーが発生します。

期待を使わないのはなぜですか?

私はvimを自動化したり、vimに入力を送信したり、そのようなものを送信したくありません。

ベストアンサー1

次のようにコードを追加しました。

  • 3つの例で動作します。
  • 待つ前に相互作用が発生します。
  • interact() {
        pid=$1
        ! ps -p $pid && return
        ls -ld /proc/$pid/fd/*
        sleep 5; kill -1 $pid   # TEST SIGNAL TO PARENT
    }
    
    run() {
        exec {in}<&0 {out}>&1 {err}>&2
        { coproc "$@" 0<&$in 1>&$out 2>&$err; } 2>/dev/null
        exec {in}<&- {out}>&- {err}>&-
        { interact $! <&- >/tmp/whatever.log 2>&1& } 2>/dev/null
        fg %1 >/dev/null 2>&1
        wait 2>/dev/null
    }
    

    fg %1すべてのコマンドに対して実行され(%1同時操作に必要に応じて変更)、一般的な状況では、次の2つのいずれかが発生します。

  • コマンドがすぐに終了すると、何もしないでinteract()fgもしないため、すぐに返されます。
  • コマンドが即座に終了しない場合は、対話することができますinteract()(たとえば、5秒後にHUPをセカンダリプロセスに送信します)、セカンダリfgプロセスは元々実行されたのと同じstdin / out / errを使用してフォアグラウンドにインポートされます(確認できます)。この金額ls -l /proc/<pid>/df)。

    最後の3つのコマンドでは、/ dev / nullへのリダイレクトは外観的です。run <command>個別に実行するときとまったく同じように見えます。command

  • おすすめ記事