Bash杀死过程错过了完成

时间:2018-10-26 14:13:45

标签: bash background-process kill bash-completion

我有一个bash主题,以懒惰的方式显示提示的各个部分。因此,它在开始时显示一组信息,然后在延迟加载信息中显示,这需要花费一些时间才能从后台进程加载和重写提示。

现在,由于如果在未渲染异步部分的情况下从当前工作目录移至另一个目录,则延迟加载的渲染是异步的,因此我们会将错误的信息放到错误的位置。示例:

enter image description here

异步渲染功能的调用者:

  # Check the async side of the prompt if available
  set +m
  _render_async &

现在为防止这种情况的发生,我添加了一项检查,以便在呈现提示之前查看是否有任何后台进程正在等待呈现不在当前目录中的异步端并杀死它。

# Check and kill any irreelvant background jobs
# Outdated background jobs are any gaudi::async_render executed on folders
# other than the current working directory $PWD  

export PROMPT_COMMAND="gaudi::kill_outdated_asyncRender; $PROMPT_COMMAND"

# Kill all background gaudi::render_async that are running in the wrong context
# Wrong context is any directory (CWD) that is not the current directory
# USAGE:
#   gaudi::kill_outdated_asyncRender

gaudi::kill_outdated_asyncRender() {
  joblist="$(jobs | grep '_render_async.*wd:' | cut -d "[" -f2 | cut -d "]" -f1 | tr '\n' ' ')"
  IFS=' '
  for job in $joblist; do kill "%$job"; done
}

这现在可以完美地工作了,我看不到错误的渲染,但是我注意到的是,现在函数的bash完成已经搞砸了,项目也没有按预期显示:

enter image description here

您可以看到她的完成元素不在同一行中,而只是坏掉了。删除kill_outdated_asyncRender可以解决此问题,但是我仍然不确定为什么会发生这种情况。

1 个答案:

答案 0 :(得分:1)

gaudi::kill_outdated_asyncRender设置IFS,但不重置它。这具有全球意义,因为它在整个bash中都用于control word-splitting behavior

  

IFS变量在shell(Bourne,POSIX,ksh,bash)中用作输入字段分隔符(或内部字段分隔符)。本质上,它是一串特殊字符,当分割输入行时,它们将被视为单词/字段之间的分隔符。

修改IFS是一种常见的模式,但是您需要重置它:

gaudi::kill_outdated_asyncRender() {
  joblist="$(jobs | grep '_render_async.*wd:' | cut -d "[" -f2 | cut -d "]" -f1 | tr '\n' ' ')"
  local oIFS=$IFS
  IFS=' '
  for job in $joblist; do kill "%$job"; done
  IFS=$oIFS
}

作为一般准则,请确保您的$PROMPT_COMMAND简单。显然存在延迟问题,但它本身很难调试。按照这些思路,我会针对性地提出一些建议,以减少发生副作用的可能性:

  1. 当派生后台进程时,将其PID记录到文件中。然后,在您的kill函数中使用此文件的内容,而不要使用jobs | grep管道。

  2. 与其在目录更改时计算这些值,不如在登录期间(在后台)定期(通过cron)预先计算它们(在后台)。您还可以使用“刷新”命令来同步更新值,以便在对所看到的内容提出疑问时始终可以获取最新的值。