2017-03-16 4 views
0

これはかなり素朴ですが、私はそれを打ち明けます。
私はbashからgimp -i -b - &でgimpを起動し、dbus信号を無限ループで読み込み、これらの信号から得られたデータをgimpに送ります。 gimp -i -b -はコマンドラインgimpを起動し、gnuplotなどのユーザ入力を待っていますが、コマンド実行後にbashからstdinにアクセスできるのでしょうか?Bashは起動後にバックグラウンドジョブのstdinに書き込みを行います。

理想的には私が仕事にそのような何かをしたいと思います:すべてのgimp cmd &が同じGIMPインスタンスに送信され

gimp -i -b - & 

dbus-monitor --profile "..." --monitor | 
while read -r line; do 
gimp -b '(mycommand '$line')' & 
done 

gimp -b '(gimp-quit 0)' & 

。 gimpインスタンスが十分に長く使用されず、必要なときに再度起動すると、gimpインスタンスを閉じることができればさらに良いでしょう。

デーモンアプリを書くことなくbashで可能ですか?

答えて

4

シンプルなソリューション

私たちは簡単なパイプを使用できます。関数にスクリプトの一部を送信するコマンドをラップしてGIMPにその出力をパイプしながら、その関数を呼び出します。

#! /bin/bash 

sendCommands() { 
    dbus-monitor --profile "..." --monitor | 
    while read -r line; do 
     echo "(mycommand $line)" 
    done 
    echo "(gimp-quit 0)" 
} 

sendCommands | gimp -i & 

sendCommandsgimp -iは、並列に実行されます。 sendCommandsが何かを印刷するたびに、何かがgimpのstdinに上陸します。
完全なスクリプトの場合はgimp -iの後に&を省略することができます。私はそれが十分な長さのために使用されていない場合はGIMPのインスタンスを閉じて、それが必要なとき、再び起動することができれば

殺害し、再起動のGimp

はさらに良いでしょう。

timeoutコマンドを使用するよりも少し複雑になります.Gimpがまだ画像を処理している間にkillしたくないからです。また、イベントの消費と対応するコマンドの送信の間にsendCommandsを殺すことは望ましくありません。

おそらく60秒ごとにdbusイベントを送信するヘルパープロセスを開始することができます。そのイベントをと呼び、としましょう。ダニはsendCommandsによっても読み取られます。間にコマンドがない2つのティックがある場合、gimpを殺す必要があります。

私たちは、FIFO(名前付きパイプとも呼ばれます)を使用して、gimpにコマンドを送信します。新しいgimpプロセスが始まるたびに、新しいFIFOも作成されます。これにより、新しいgimpプロセスを対象とするコマンドも新しいプロセスに送信されます。 gimpが保留中の操作を60秒以内に完了できない場合、同時に2つのgimpプロセスが存在する可能性があります。 dbus-monitor ... | while ... doneが今while ... done < <(dbus-monitor ...)のように書かれていること

#! /bin/bash 

generateTicks() { 
    while true; do 
     # send tick over dbus 
     sleep 60 
    done 
} 

generateTicks & 

gimpIsRunning=false 
wasActive=false 
sleepPID= 
fifo= 

while read -r line; do 
    if eventIsTick; then # TODO replace "eventsIsTick" with actual code 
     if [[ "$wasActive" = false ]]; then 
      echo '(gimp-quit 0)' > "$fifo" # gracefully quit gimp 
      gimpIsRunning=false 
      [[ "$sleepPID" ]] && kill "$sleepPID" # close the FIFO 
      rm -f "$fifo" 
     fi 
     wasActive=false 
    else 
     if [[ "$gimpIsRunning" = false ]]; then 
      fifo="$(mktemp -u)" 
      mkfifo "$fifo" 
      sleep infinity > "$fifo" & # keep the FIFO open 
      sleepPID="$!" 
      gimp -i < "$fifo" & 
      gimpIsRunning=true 
     fi 
     echo "(mycommand $line)" > "$fifo" 
     wasActive=true 
    fi 
done < <(dbus-monitor --profile "..." --monitor) 

echo '(gimp-quit 0)' > "$fifo" # gracefully quit gimp 
[[ "$sleepPID" ]] && kill "$sleepPID" # close the FIFO 
rm -f "$fifo" 

は注意してください。どちらのバージョンもdbusの出力をループするという点で同じことをしますが、パイプ|のバージョンではループ内にグローバル変数を設定することができないサブシェルが作成されます。詳しい説明は、SC2031を参照してください。

+0

ありがとうございます@ソコウイ、それは素晴らしい答えです!私はちょうど間違いを犯しました。まず、gimpを実行し、stdinからのユーザ入力を待つのは 'gimp -i'だけではなく、' gimp -i -b --'です。第二に、答えの最後の部分は、gimpだけでなく、一般的なアプリにも適しています。しかし、gimpの場合には利点があります。 '(gimp-message(string-append"処理が完了しました!)) 'でstderrに警告を表示させることができます。だから私は今、アイドルモードに入っているという事実をgimpに伝えるように強制することができます。 – truf

+0

私はsendCommandsのようなものを実行できるはずです。 gimp -i -b-3>&gt;&2&gt;&3 | processReply& 'とprocessreeply()'の処理に関するgrepメッセージが表示されます。したがって、 'gimpIsRunning'の中で、私は' gimpIsWorking'をグローバルに可変にでき、 'timeout'アプローチに固執する必要があります。もちろん、このようなアプローチはgimpのみで可能であり、一般的ではありません。この場合、結果コードが簡単になるのだろうか? – truf

+0

良い点。残念ながら、gimpのstderrをスキャンするときには、それほど単純ではありません。私たちは事前にタイムアウトを知っていないので(これは将来の着信ジョブに依存します)、 'timeout'はまだ役に立たないです。 'sendCommands | gimp ... | processReply& 'も使用できません。パイプラインの途中にあるgimpプロセスを停止し、新しいgimpプロセスに置き換えることはできません。 gimpの標準エラーをスキャンするだけの利点:一度に1つのgimpプロセスしか実行しないようにすることができます。 – Socowi

関連する問題