没有办法满足这些限制

没有办法满足这些限制

zsh 提供了一些不错的钩子函数,包括chpwd在用户更改目录后运行函数。

# zsh only
function greet() { echo 'hi'; }
chpwd_functions+=("greet")
cd .. # hi
pushd # hi
popd  # hi

我正在尝试在 bash 中模拟这一点。

限制条件:

  • 它必须在交互式和非交互式 shell 中工作,我认为这意味着它不能依赖于类似的东西$PROMPT_COMMAND
  • 它无法重新定义cd,因为我希望它适用于任何更改目录的命令(例如,pushdpopd
  • 它必须运行用户的命令,所以trap "my_function" DEBUG不起作用,除非我可以以某种方式在那里说,“首先运行$BASH_COMMAND我们被困的命令,然后也执行此操作......”我发现我可以避免自动运行$BASH_COMMAND 如果 extdebug已启用trap 函数返回 1,但我认为我不想强制extdebug,并且返回1成功(但已修改)的命令似乎是错误的。

最后一部分 - “按照用户的命令运行” - 目前让我感到困惑。如果我在每个命令后运行一个函数,我可以让它检查自上次检查以来目录是否已更改。例如:

function check_pwd() {
  # true in a new shell (empty var) or after cd
  if [ "$LAST_CHECKED_DIR" != "$PWD" ]; then
    my_function
  fi
  LAST_CHECKED_DIR=$PWD
}

我走在正确的道路上,还是有更好的方法?用户更改目录后如何在 bash 中运行命令?

答案1

没有办法满足这些限制

看起来在我的限制下,bash 中没有办法解决这个问题。一般来说,可能的解决方案是:

  • 覆盖cdpushdpopd,以便任何更改目录的命令都将首先运行挂钩函数。但这可能会产生问题,因为 1) 覆盖必须像原始命令一样小心地完成并返回相同的退出代码,2) 如果多个工具采用这种方法,它们就不能很好地协同工作
  • 覆盖可能随环境更改而运行的所有命令,以首先运行挂钩函数。这很难,因为有很多这样的命令
  • trap 'my_function' DEBUG这样每个命令都会运行钩子函数。这是次优的,因为 1) 它在每个命令之前运行,2) 它运行 cd,而不是在3)之后只能有一个调试功能,因此如果另一个工具使用这种方法,它们就不能很好地协同工作
  • 重新定义$PROMPT_COMMAND先运行钩子函数。这是次优的,因为它不能在非交互式 shell 中工作,而且如果另一个工具定义了提示命令,它们就不能很好地协同工作。

简而言之,似乎唯一好的解决方案是 bash 提供类似 zshell 的chpwd_functions钩子之类的东西,但似乎不可能正确地模拟它。

答案2

如果维护者不喜欢您更改 cd 的定义,另一个选择是重新定义使用此目录内环境的所有命令:

for c in cmd1 cmd2 cmd3 cmd4 cmd5 ; do
    eval "$c() { check_pwd ; command $c \"\$@\" ; }"
done

这将非常有效,因为 PWD 挂钩和目录内配置仅在需要时才会被处理。

在您的示例 check_pwd 函数中,我可能会更改:

my_function

到:

my_function "$PWD"

为了传递新的cwd(可能更加模块化,可测试)。

答案3

安装inotify 工具根据你的分布。

inotifywait -emodify,create,delete -m /path/to/directory | while read line; do service httpd reload; done

httpd在我的示例中,如果指定目录中发生任何更改(修改、创建、删除),以下命令将重新启动。

相关内容