zsh 提供了一些不错的钩子函数,包括chpwd
在用户更改目录后运行函数。
# zsh only
function greet() { echo 'hi'; }
chpwd_functions+=("greet")
cd .. # hi
pushd # hi
popd # hi
我正在尝试在 bash 中模拟这一点。
限制条件:
- 它必须在交互式和非交互式 shell 中工作,我认为这意味着它不能依赖于类似的东西
$PROMPT_COMMAND
- 它无法重新定义
cd
,因为我希望它适用于任何更改目录的命令(例如,pushd
和popd
) - 它必须运行后用户的命令,所以
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 中没有办法解决这个问题。一般来说,可能的解决方案是:
- 覆盖
cd
、pushd
和popd
,以便任何更改目录的命令都将首先运行挂钩函数。但这可能会产生问题,因为 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
在我的示例中,如果指定目录中发生任何更改(修改、创建、删除),以下命令将重新启动。