在构建 bash 提示符时终止后台进程

Killing a background process while building a bash prompt

我已经设法让我的 bash 提示延迟加载一些组件以获得异步渲染的感觉。延迟加载功能作为后台进程运行 (render_async &).

从下面的截屏视频中,您可以看到提示实际上是如何立即加载一部分和另一部分的 "lazy loads"。但是,我注意到,如果您在加载异步部分之前更改目录,新提示将被错误的上下文覆盖。

我解决这个问题的思路如下:

我在我的异步命令中添加了一个睡眠来模拟它,我可以看到后台进程挂起。

[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: no such job.

当我在 shell 中执行相同的 kill 命令时,它运行良好。

如有任何帮助,我们将不胜感激。

其他想法

我尝试命名我的分叉进程(通过将 CWD 附加到函数名称来命名每个异步进程)灵感来自 https://askubuntu.com/questions/153900/how-can-i-start-a-process-with-a-different-name 其中:

bash -c "exec -a MyUniqueProcessName <command> &" replaces the current shell, no new process is created, that's why I'm starting a new shell to call exec.

Then you can kill the process with:

pkill -f MyUniqueProcessName You can start more than one process under the same name, then pkill -f will kill all of them.

但这一直告诉我我试图传递给 <command> 的异步函数没有找到,我怀疑它与它是一个自定义函数的事实有关,那就是分叉一个新的 bash 进程,但我不是这里的专家。

谢谢

管道创建一个隐式子shell,因此在 kill 是 运行 的管道到 while 循环中,来自父项的作业是不可见的。怎么样,这至少会杀死第一份工作?

job="$(jobs | grep 'render_async.*wd:' | cut -d "[" -f2 | cut -d "]" -f1)"
kill "%$job"

在我的测试中,$(...) 发生在当前 shell 中,至少最初是这样,因此作业 table 是可见的。示例:

$ 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]+).*$//'|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]+).*$//'|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-函数环境中是否有所不同。