在生成bash提示符时终止后台进程

在生成bash提示符时终止后台进程,bash,shell,command-prompt,background-process,kill,Bash,Shell,Command Prompt,Background Process,Kill,我已经设法使我的bash提示符延迟加载一些组件,使其具有异步渲染的感觉。延迟加载函数作为后台进程运行,具有(render\u async&) 从下面的屏幕广播中,您可以看到提示符实际上是如何立即加载部分内容以及其他“延迟加载”内容的。但是,我注意到,如果在加载异步部分之前更改目录,新的提示将被错误的上下文覆盖 我的修复思路如下: 使用作业命令检查后台进程 我发现jobs命令在不在当前工作目录后台的进程旁边显示一个wd: 查找并杀死所有具有该模式的后台进程,以避免这种覆盖 我在async命令

我已经设法使我的bash提示符延迟加载一些组件,使其具有异步渲染的感觉。延迟加载函数作为后台进程运行,具有
(render\u async&)

从下面的屏幕广播中,您可以看到提示符实际上是如何立即加载部分内容以及其他“延迟加载”内容的。但是,我注意到,如果在加载异步部分之前更改目录,新的提示将被错误的上下文覆盖

我的修复思路如下:

  • 使用
    作业
    命令检查后台进程
  • 我发现jobs命令在不在当前工作目录后台的进程旁边显示一个
    wd:
  • 查找并杀死所有具有该模式的后台进程,以避免这种覆盖
我在async命令中添加了一个sleep来模拟它,我可以看到后台进程挂起

[1]   Running                 render_async &
[2]-  Running                 render_async &  (wd: ~/Projects/My Personal Space/blog-core)
[3]+  Running                 render_async &
我接着写道:

  jobs | grep 'render_async.*wd:' | cut -d "[" -f2 | cut -d "]" -f1 | while read -r line ; do
    kill "%$line"
  done
理论上应该解析其他目录中后台作业的id并杀死它们。然而,在实践中,我不断得到上面的例子
kill:%2:没有这样的工作

当我在shell本身中执行相同的
kill
命令时,它工作得非常好

非常感谢您的帮助

其他想法 我曾尝试命名我的分叉进程(通过将CWD附加到函数名来命名每个异步进程),其灵感来源于:

bash-c“exec-a MyUniqueProcessName&”
当前的shell没有创建新的进程,这就是我开始的原因 调用exec的新shell

然后,您可以使用以下方法终止该进程:

pkill-f MyUniqueProcessName您可以在下面启动多个进程 如果名称相同,那么pkill-f将杀死所有这些人

但这一直告诉我,我试图传递给
的异步函数找不到,我怀疑这与它是一个自定义函数,正在派生一个新的bash进程有关,但我不是这里的专家


感谢

管道创建了一个隐式子shell,因此在运行
kill
的循环时,来自父对象的作业在管道中不可见。这个怎么样,至少会毁掉第一份工作

job="$(jobs | grep 'render_async.*wd:' | cut -d "[" -f2 | cut -d "]" -f1)"
kill "%$job"
在我的测试中,
$(…)
发生在当前shell中,至少最初是这样,因此作业表是可见的。例如:

$ cat &
[1] 8296
$ jobs
[1]+  Stopped                 cat
$ echo "$(jobs| cut -d "[" -f2 | cut -d "]" -f1|head -1)"
1
(顺便问一下,你想杀死的工作总是有相同的工作编号吗?你能不能只硬编码
%2
,或者不管它是什么?)

编辑多作业:

joblist="$(jobs| sed -E 's/^[^0-9]*([0-9]+).*$/\1/'|tr '\n' '@')"
    # E.g., 1@2@
IFS='@'     # Split on @
for job in $joblist     # No double-quotes!
do
    kill "%$job"
done
shell提示符的工作示例:

$ cat&
[1] 8824
$ cat&
[2] 6452

[1]+  Stopped                 cat
$ jobs
[1]-  Stopped                 cat
[2]+  Stopped                 cat
$ joblist="$(jobs| sed -E 's/^[^0-9]*([0-9]+).*$/\1/'|tr '\n' '@')"
$ IFS=@
$ for job in $joblist; do kill "%$job" ; done

[1]-  Stopped                 cat

[2]+  Stopped                 cat
$ jobs
[1]-  Terminated              cat
[2]+  Terminated              cat
$ jobs
$
我选择
@
作为分隔符,因为我认为它对shell没有任何特殊意义


我不知道这是否会对PS1功能环境产生影响。

您使用的终端是否提供标题窗口或其他可以写入状态的带外位置?当然,改进这种方法是可能的,但我不确定您是否能够使其完全健壮:如果一个新流程认为它拥有终端,但您的旧shell子流程仍在打印,则冲突是不可避免的。谢谢@charlesduff的评论。我正在使用MacOSX终端,但我很想看看如何改进它,使其健壮,而据我所知,会生成一个隐式子shell,因此在while中的
kill
可能无法看到作业。@cxw,不,
while
不会创建子shell;在管道连接到
while
时,负责的是管道,而不是
while
。(不过,您是对的,它不会是同一个shell实例,也不会有相同的作业表;对于非交互脚本,可以使用
lastpipe
更改该行为,但在启用作业控制时它不可用)…通常,当您从bash启动某个对象并希望稍后将其杀死时,您应该保留pid:
foo&foo\u pid=$
允许您在以后
杀死“$foo\u pid”
(如果kill-0“$foo\u pid”&>/dev/null;则检查它是否仍在使用
运行,
等)。作业编号是动态的,可以更改。。现在我将尝试你的方法:)即使使用你的第一种方法,我仍然得到
-bash:kill:%:没有这样的工作
。我不确定作为PS1函数执行此操作是否与itok有趣有关。。问题似乎不是访问作业表,因为当我硬编码
kill%2
时,它工作了,作业被终止了。动态地这样做似乎是一种挑战problem@AhmadAssaf使用多作业支持编辑。除非多任务方式有效,否则请使用MCVE更新您的问题好吗?使用for do the job@cxw的技巧。似乎while的子过程是cuplrit。然而,我现在可能遇到了另一个问题。为了抑制后台作业的状态,我运行它时用括号括起来
(render\u async&)
。。当我这样做时,杀戮不会发生,但当我移除它们时,一切都如预期的那样工作。知道为什么吗?