Bash 在启动后写入后台作业的标准输入

Bash write to background job's stdin after its launch

这很天真,但我会试一试。
我想从 bash 和 gimp -i -b - & 启动 gimp,然后在无限循环中读取 dbus 信号,然后从这些信号获得的 post 数据返回到我启动的 gimp。 gimp -i -b - 启动命令行 gimp 并等待用户输入,如 gnuplot 等。但是在命令执行后是否可以从 bash 访问其标准输入?

理想情况下,我想要这样的东西工作:

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 实例。 如果我可以关闭 gimp 实例,如果它没有被使用足够长的时间,并在需要时重新启动,那就更好了。

是否可以使用 bash 而无需编写一些守护程序应用程序?

简单的解决方案

你可以给我们一个简单的管道。将发送部分脚本的命令包装到一个函数中,并在将其输出通过管道传输到 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 的标准输入中。
如果那是您的完整脚本,您可以省略 gimp -i.

之后的 &

杀死并重新启动 Gimp

Would be even better if I could close gimp instance if it's not used for long enough and start again when it's needed.

这比仅使用 timeout 命令要复杂一些,因为我们不想在 gimp 仍在处理一些图像时终止它。我们也不希望在消耗事件和发送相应命令之间终止 sendCommands

也许我们可以启动一个辅助进程来每 60 秒发送一个 dbus 事件。假设所述事件被称为 ticksendCommands 也读取报价。如果中间有两个没有命令的滴答声,gimp 应该被杀死。

我们使用 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