2017-03-16 48 views
0

這是相當天真的,但我會給它一個鏡頭。
我想從bash中啓動gimp與gimp -i -b - &,然後在無限循環中讀取dbus信號,並將從這些信號中獲得的數據發回給我啓動的gimp。 gimp -i -b -啓動命令行gimp並等待用戶輸入,例如gnuplot等。但是可以在命令執行後從bash訪問其標準輸入嗎?Bash在啓動後寫入後臺作業的stdin

理想我想這樣的事情工作:

gimp -i -b - & 

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

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

所有gimp cmd &被髮送到同一個瘸子實例。 如果我可以關閉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之後省略&

殺死並重啓瘸子

甚至會更好,如果,如果它不是用足夠長的時間,我可以關閉瘸子實例,並在需要時重新啓動。

這比使用timeout命令稍微複雜一些,因爲我們不想在處理某些圖像時殺死gimp。我們也不想在消耗事件和發送相應命令之間終止sendCommands

也許我們可以啓動一個幫助程序來每60秒發送一次dbus事件。讓我們說的事件被稱爲勾號。刻度也由sendCommands讀取。如果兩個滴答聲之間沒有命令,則應該殺死芯片。

我們使用FIFO(也稱爲命名管道)向gimp發送命令。每當新的gimp進程開始時,我們也會創建一個新的FIFO。這確保針對新gimp進程的命令也被髮送到新進程。萬一gimp無法在60秒內完成掛起的操作,可能同時有兩個gimp進程。

#! /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-monitor ... | while ... done現在寫成while ... done < <(dbus-monitor ...)。兩種版本在循環dbus輸出方面都做了同樣的事情,但管道|的版本創建了一個不允許在循環內設置全局變量的子shell。有關更多解釋,請參閱SC2031

+0

謝謝@Socowi,這是一個很好的答案!我只需要添加兩個註釋:首先,我犯了一個錯誤,它是一個'gimp -i -b - '不僅僅是'gimp -i',它運行gimp並等待來自stdin的用戶輸入。其次,你答案的最後部分適用於任何通用應用程序,不僅僅是gimp。但是在gimp的情況下,我們有一個優勢 - 我們可以使用'(gimp-message(string-append「處理已完成!))''來打印警告。所以我想我們可以強迫gimp來傳達它現在處於空閒模式的事實。 – truf

+0

我想我應該可以運行類似'sendCommands |的東西gimp -i -b - 3>&1 1>&2 2>&3 | processReply&'和grep有關處理結束的消息在'processReply()'中結束。與'gimpIsRunning'之間因此我應該能夠得到'gimpIsWorking'全球varaiable與'timeout'辦法堅持下去。當然這種方法只能用gimp而不是一般情況。我想知道在這種情況下結果代碼是否會更簡單? – truf

+0

好點。不幸的是,當掃描gimp的stderr時,事情並沒有多少簡單。因爲我們不知道提前超時(這取決於傳入作業從未來)'timeout'是沒有用的依然。 'sendCommands | gimp ... | processReply&'也不能使用。我們不能停止並用新的gimp過程替換管道中間的gimp進程。掃描gimp的stderr只有好處:我們可以確保一次只運行一個gimp進程。 – Socowi