$ PWD发生任何更改后,如何在bash中运行命令?


10

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 if 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中运行命令?


3
为什么不重新定义cdpushdpopd?有几种其他方法可以更改目录?
jw013 2014年

@ jw013此代码旨在进入一个开源项目,在该项目中,维护者已明确列出了不重新定义cd的原则。
内森·朗

另外-“还有许多其他方法可以更改目录”-我不知道,这是我不希望依赖于明确列出它们的另一个原因。
内森·朗

为什么要这样做?您的函数可能会制动许多程序(C,Java,..)。在我使用的脚本中,MYBIN=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )请不要更改受信任的Unix命令。
沃尔特A

1
@NathanLong 仅适用于我的操作系统。此处的操作系统似乎无关紧要。操作系统重要吗?在您的问题中,关键是外壳,您似乎特别在询问bash,它在所运行的所有操作系统上的工作原理几乎相同。
jw013 2014年

Answers:


2

没有办法满足这些限制

似乎没有办法用我的约束来解决bash中的这个问题。通常,可能的解决方案是:

  • 覆盖cdpushdpopd,以便任何更改目录的命令将首先运行hook函数。但这可能会引起问题,因为1)覆盖操作必须像原始命令一样小心地按Tab键完成操作,并返回相同的退出代码,并且2)如果有多个工具采用了这种方法,它们将不能很好地配合使用
  • 覆盖可能与环境更改一起运行的所有命令,以首先运行hook函数。这很困难,因为有许多这样的命令
  • trap 'my_functionDEBUG so that every command will run the hook function. This is suboptimal because 1) it runs before every command, 2) it runs *before*cd`,而不是3)之后只能有一个调试功能,因此,如果另一种工具使用这种方法,它们将不能很好地配合使用
  • 重新定义$PROMPT_COMMAND以首先运行挂钩函数。这是次优的,因为它不适用于非交互式外壳,并且如果使用其他工具定义了提示命令,它们将不能很好地配合使用。

简而言之,似乎唯一的好方法是bash提供zshell的chpwd_functions钩子,但似乎无法正确模拟。


1

如果维护者不喜欢更改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(可能更具模块化,可测试性)。


“重新定义使用此目录内环境的所有命令”不幸的是,我无法预测到这一点。
内森·朗

0

根据您的发行版安装inotify-tools

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.