Bash中是否有钩子可以找出当前工作目录更改的时机?

20

我通常使用zsh,它提供了chpwd()钩子函数。也就是说:如果cd内置命令改变了当前工作目录(cwd),那么如果存在chpwd()方法,zsh会自动调用它。这允许设置依赖于cwd的变量和别名。

现在我想将我的.zshrc中的这部分内容移植到bash,但发现bash不认识chpwd()。在bash中是否已经有类似的功能?我知道重新定义cd可以解决问题(见下文),但我希望获得更优雅的解决方案。

function cd()
{
    builtin cd $@
    chpwd
}

5
为什么 cd 函数不够优雅? - user123444555621
我喜欢你的解决方案,看起来很简洁! - antonagestam
Unix&Linux上的类似问题。您的解决方案与我使用的相同,我不明白为什么您认为它不优雅。 - Gilles 'SO- stop being evil'
3
@user123444555621说:首先,使用function cd并不优雅,因为它仅处理cd。如果您使用pushdpopd更改目录,则还必须将它们包装起来。这并不是无法克服的障碍,但使用zshchpwd钩子意味着您只需定义该钩子,而无需详尽地确定工作目录可能发生的所有可能方式,同时仍然不需要像PROMPT_COMMAND那样每次显示提示符时运行(可能昂贵的)代码。 - ShadowRanger
2个回答

14
你需要使用DEBUG 'trap'或'PROMPT_COMMAND'。
例子:
trap chpwd DEBUG        # calls the function before each command

PROMPT_COMMAND=chpwd    # calls the function after each command

请注意,PROMPT_COMMAND 中定义的函数在每个提示符之前都会运行,即使是空提示符。


2
一个小的示例代码片段会很好。 - Peter Lyons
1
@marcioAlmada:我添加了示例。 - Dennis Williamson
伟大的提示; 需要注意的事项:DEBUG陷阱在每个简单命令之前执行,这意味着:(a)如果您的命令行是一个列表-例如,:; :,则陷阱命令对该列表中的每个命令都会执行;(b)如果您还设置了$PROMPT_COMMAND,那么在那里定义的命令也会触发陷阱。 - mklement0
由于 $PROMPT_COMMAND 可能已经以 ; 结尾,可能带有尾随空格(实际上,OSX 就是这样做的: "update_terminal_cwd; ");如果您盲目地在该事件中追加 ;,将导致两个连续的 ;,从而引起语法错误。我的命令可以防止这种情况发生。 - mklement0
使用PROMPT_COMMAND=chpwd或其变体的好处与zsh相比是,当终端刚打开时,zsh上的chpwd钩子不会触发,但PROMPT_COMMAND会触发。 - Thom
显示剩余5条评论

3
更好的解决方案可能是定义自定义chpwd钩子。 与其他现代shell相比,Bash没有完整的钩子系统设计。在Bash中,PROMPT_COMMAND变量被用作钩子函数,它相当于ZSH中的precmd钩子、Fish中的fish_prompt。目前为止,我所知道的唯一拥有内置chpwd钩子的shell是ZSH。

PROMPT_COMMAND

如果设置了该变量,它将被解释为每个主提示符($PS1)打印之前要执行的命令。

https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Bash-Variables

Bash中的chpwd钩子

提供了一种技巧,在Bash中基于PROMPT_COMMAND设置一个等效于chpwd的钩子。
# create a PROPMT_COMMAND equivalent to store chpwd functions
typeset -g CHPWD_COMMAND=""

_chpwd_hook() {
  shopt -s nullglob

  local f

  # run commands in CHPWD_COMMAND variable on dir change
  if [[ "$PREVPWD" != "$PWD" ]]; then
    local IFS=$';'
    for f in $CHPWD_COMMAND; do
      "$f"
    done
    unset IFS
  fi
  # refresh last working dir record
  export PREVPWD="$PWD"
}

# add `;` after _chpwd_hook if PROMPT_COMMAND is not empty
PROMPT_COMMAND="_chpwd_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}"

使用方法

# example 1: `ls` list directory once dir is changed
_ls_on_cwd_change() {
  ls
}

# append the command into CHPWD_COMMAND
CHPWD_COMMAND="${CHPWD_COMMAND:+$CHPWD_COMMAND;}_ls_on_cwd_change"

# or just use `ls` directly
CHPWD_COMMAND="${CHPWD_COMMAND:+$CHPWD_COMMAND;}ls"

来源:在我的GitHub代码片段中创建Bash的chpwd钩子的等效方法


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接