条件执行 - 启动持久子进程和协程

条件执行 - 启动持久子进程和协程

Bash 中使用条件执行来根据子进程的退出状态控制脚本的流程。然而,在某些情况下,子进程(应用程序)在后台启动,用于交互目的,因此没有退出,也没有退出状态,直到它关闭。

考虑一些例子,比如启动 pdf 查看器,多普夫夫。考虑第一种情况,其中存在一个文件 example.pdf:

$ mupdf example.pdf &
[1] 16220

这可行,所以让我们尝试条件执行:

$ mupdf example.pdf & && echo TRUE
bash: syntax error near unexpected token '&&'

嗯。好吧,让我们尝试另一种(人为的)方法,试图避免错误:

$ if mupdf example.pdf &; then echo TRUE; fi
bash: syntax error near unexpected token ';'

怎么样:

$ if (mupdf example.pdf &); then echo TRUE; fi
TRUE

这看起来很有希望,但是我们尝试第二种情况,使用一个不存在的文件:

$ mupdf nofile.pdf &
[1] 16282
$ error: cannot open nofile.pdf
error: cannot load document 'nofile.pdf'
mupdf: error: cannot open document

$ if (mupdf nofile.pdf &); then echo TRUE; fi
TRUE
$  error: cannot open nofile.pdf
error: cannot load document 'nofile.pdf'
mupdf: error: cannot open document

该构造也不起作用。因此,通常的条件执行方法不起作用,因为没有退出状态。但我注意到,在成功和不成功的情况下,最初都会创建一个 pid(多普夫夫在第二种情况下无法打开 - 启动最终失败)。

所以尝试另一种方法,等待看看后台pid会发生什么,所以我们编写了以下脚本:

#!/usr/bin/env bash

# usage: ./show <file>.pdf

mupdf "$1" &>/dev/null &
sleep 2
if kill -0 $! &>/dev/null
then 
  echo TRUE
else
  echo FALSE
fi

# end file

并测试第一种情况:

$ ./show example.pdf  # case 1
[1] 16602
TRUE

没关系。现在来说第二种情况:

$ ./show nofile.pdf   # case 2
[2] 16699
[2]+  Exit 1                  mupdf nofile.pdf &> /dev/null
FALSE

嗯,这也有效。但这似乎是一种非常复杂的检查进程的方法,如果启动需要更多时间(超过 2 秒),则可能会失败。所以我的问题是,有没有更好(更干净)的方法来解决这个问题?

答案1

我找到了许多与此主题类似的主题,考虑使用以下内容xdo工具控制面板用于测试持久窗口应用程序或其他持久子进程的启动。但使用这些似乎是不必要的复杂化。下面的解决方案将允许有条件地执行持久子流程。它利用半秒的睡眠持续时间。如果感兴趣的子进程需要更长的时间才能成功启动,则需要相应增加此持续时间。

bash 源文件发射

#/usr/bin/env bash

# launch : will allow launching a windowed application or persistent
# sub-process in the background so that conditional execution can be
# applied to determine whether or not it has launched successfully -
# dependencies: GNU coreutils (sleep), util-Linux (kill)

# usage: ./launch process arg_1 .. arg_n && echo TRUE || echo FALSE

$@ &>/dev/null & sleep 0.5 && kill -0 $! 2>/dev/null

# end file

以便:

$ ./launch mupdf example.pdf && echo TRUE || echo FALSE
TRUE

$ ./launch mupdf nofile.pdf && echo TRUE || echo FALSE
FALSE

作为此信息的后记,我认为包含以下建议会很有用:麦克塞夫在对开篇文章的评论中。

鉴于上述构造完成了当前任务,麦克塞夫指出它可能会导致其他问题,因为它不会将信号传播到调用脚本;相反,它会忽略并丢弃它。这是一个非常重要的观察。

信号是进程间通信的关键元素,并且可以导致事件驱动脚本的可能性。因此,为了获得更健壮和有效的脚本,麦克塞夫建议采用以下方法来捕获信号,以便可以传播信号:

{ mupdf some.pdf || kill -"$(($?&127))" "$$"; } &

其中$?&127允许操作 1 到 128 个可能的信号 (POSIX),我的 Debian 系统有 64 个,因此信号掩码可以$?&63代替。


因此,作为结束语,对于非常简单的脚本,进程间通信不感兴趣,建议发射可能很有用,但对于更多的事情,特别是在进程间通信很重要的情况下,捕获(并传播)信号,如建议的麦克塞夫

答案2

作为单行:

mupdf example.pdf & echo mupdf is now in the background; wait $! && echo FINISHED successfully

相关内容