2017-03-16 50 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