每次执行命令时更新zsh提示符怎么做?

7

TLDR;

我需要一种方法,使得每次执行命令时自动引入.zshrc。必须在每次执行命令时更新PROMPT以显示提示符中的相关信息。

原因

我使用Watson cli来跟踪时间。在我的以前的Bash设置中,我在提示符($PS1)前面添加了一个指示器,指示计时器是否正在运行(红色/绿色)。我已经在Oh My Zsh中模仿了这个功能,如下所示(在主题文件中):

WATSON_DIR="$HOME/Library/Application Support/watson"
watson_status() {
    local txtred="${fg_bold[red]}"
    local txtgrn="${fg_bold[green]}"
    local txtrst="${reset_color}"

    # Started
    local status_color="$txtgrn"

    # Stopped
    if [[ $(cat "$WATSON_DIR/state") == '{}' ]]; then
        status_color="$txtred"
    fi
    echo -e "$status_color""◉""$txtrst"
}

PROMPT="╭── %{$(watson_status) $fg_bold[green]%}%~%{$reset_color%}$(git_prompt_info) ⌚ %{$FG[130]%}%*%{$reset_color%}
╰─➤ $ "

当前问题

图标将指示在执行 .zshrc 时状态的颜色。例如,如果计时器正在运行且图标正确地指示为绿色,则停止计时器不会使图标变成红色。为了看到图标改变颜色,我必须源化 .zshrc。

这表明每次执行命令时都需要运行函数 watson_status(),以便在命令执行时给出最新状态。


这可能不是你想听到的答案,但是zsh(以及任何其他shell)并不意味着以这种方式使用(否则,shell命令可能会被减慢或恶意更改用于其他目的)。如果您想检查“某事”的状态,则唯一可靠的方法是1 / 使用cron作业2 / 如果您想在运行shell窗口时立即收到问题通知,请使用“wall”广播,并结合电子邮件或短信文本。 - Alex
在我转换到zsh之前(当我使用bash时),我可以使用PS1轻松完成此操作,而不会出现任何问题。我所做的就是在watson_status()上方使用完全相同的函数,然后导出PS1。当然,在使用“oh my zsh”时,功能是不同的,但我不明白为什么不能像以前那样完成它。 - Tycholiz
我并不是说这是不可能的,我只是认为那可能不是正确的方式。如果每个用户执行的shell命令都会额外执行一个命令,那么有什么可以防止恶意代码的插入呢? - Alex
1
请检查以下内容,这可能是您正在寻找的:https://superuser.com/questions/735660/whats-the-zsh-equivalent-of-bashs-prompt-command - Alex
2
当定义了PROMPT但未显示时,将调用watson_status。请使用单引号(进行必要的调整),就像在bash中一样。此外,请阅读man zshmisc中的precmd钩子,以按需定义您的提示符(类似于bash中的PROMPT_COMMAND),这就是Alex所提到的问题所涉及的内容。 - chepner
@chepner 您说得完全正确,我曾经认为单引号和双引号是可以互换的。非常感谢您的帮助! - Tycholiz
1个回答

14

我最近将一些bash提示代码从OSX Big Sur迁移到zsh,这是我需要知道的两件大事:

  • 在您的.zshrc中添加setopt PROMPT_SUBST。这“允许在提示符中使用函数”
  • 在定义PS1 / PROMPT时请使用单引号。如果使用双引号,则整个字符串将在终端启动时评估一次,然后每次命令更改时都会“重新执行”该评估值。但你希望重新评估函数,而不是终端创建时函数的输出。

我用来确认它是否正常工作的最简单的例子:

# print_epoch() { date '+%s' }

# this is what you want
# export PS1='$(print_epoch) > '

# this is not what you want
# export PS1="$(print_epoch) > "

值得注意的是,PS1和PROMPT可以互换使用。

额外信息:

在这里分享一下我的可接受的echo my user、directory和git分支PROMPT,其中包含一些颜色和漂亮的叶子图案:

parse_git_branch() {
  git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/'
}

setopt PROMPT_SUBST
autoload -U colors && colors
export PROMPT='%n %~ %F{blue}$(parse_git_branch)%f > '

注意:

  • %n 打印用户名
  • %~ 打印相对于主目录的路径
  • %F{blue} 将文本颜色更改为蓝色
  • %f 重置颜色

文档:http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html#Visual-effects


1
我不知道 PROMPT 和 PS1 有什么区别?实际上它们是没有区别的。PROMPTPS1 的别名。你对其中一个设置的任何值都会反映在另一个变量中。 - Marlon Richert
1
你可以使用 %F{blue} 代替 %{$fg[blue]%},而 %b 则是重置所有高亮显示。因此不需要定义自己的 $reset_color 变量。 - Marlon Richert
@MarlonRichert 我已经采纳了你的反馈。我无法让 %b 正常工作,但是 %F 可以作为颜色重置。 - zayquan
抱歉,似乎 %b 会重置所有高亮显示,除了颜色。我的错误。重置颜色的正确方式是使用 %f。我已经向您的答案提交了一个编辑。 - Marlon Richert

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