zsh不能重新计算我的Shell提示符

20

这可能有点小众,但我最近切换到了zsh,并且在定制我的Shell提示符时遇到了问题。

我的.zshrc的一部分看起来像这样:

# keeping this simple right now by just printing the date, but imagine this function would look for something specific when moving to a new directory each time
function parse_special {
    print $(date)
}

autoload -U colors && colors
PS1="%{$fg[green]%}%n@%m %{$fg[blue]%}%c %{$fg[yellow]%}%{$(parse_special)%} %{$reset_color%}%# "

当我启动终端时,一切看起来都很好;我的提示符与我预期的一样:

me@someHost ~ Wed Aug 8 22:56:22 PDT 2012 %

但是,当我cd到另一个目录时,似乎我的parse_special函数没有再次被调用来重新计算我的自定义提示(注意日期没有改变):

me@someHost ~ Wed Aug 8 22:56:22 PDT 2012 % cd .ssh 
me@someHost .ssh Wed Aug 8 22:56:22 PDT 2012 % cd ../workspace 
me@someHost workspace Wed Aug 8 22:56:22 PDT 2012 % 

有没有办法告诉zsh每次显示提示符之前都重新计算一次?

非常感谢任何建议。


回复cjhveal:

似乎PS1不喜欢由单引号值设置。我尝试了以下内容:

local tp1="%{$fg[green]%}%n@%m%{$reset_color%}"
PS1="${tp1}"
print "PS1 set by tp1: ${PS1}"
local tp2='%{$fg[green]%}%n@%m%{$reset_color%}'
PS1="${tp2}"
print "PS1 set by tp2: ${PS1}"

我得到了这个输出

#inner stuff was green
PS1 set by tp1: %{%}%n@%m%{%}
#everything was uncolored
PS1 set by tp2: %{$fg[green]%}%n@%m%{$reset_color%}
我还要补充一点,参考cjhveal的建议,这是我实际尝试过的代码。同样地,单引号似乎会导致问题。
function parse_special {    
    print $(date)
}

autoload -U colors && colors
local prompt_user='%{$fg[green]%}%n@%m%{$reset_color%}'
local prompt_root='%{$fg[red]%}%n@%m%{$reset_color%}'
local prompt_dir='%{$fg[blue]%}%c%{$reset_color%}'
local prompt_special='%{$fg[yellow]%}%{$(parse_special)%}%{$reset_color%}'
PS1="${prompt_user} ${prompt_dir}${prompt_special}%# "
2个回答

25

当我在自定义我的 zsh 提示符时,遇到了相同的问题。

我认为这是因为在初始化提示符时,shell 会将值插入字符串中一次。随后的重新加载会在您的提示符中具有常量字符串,而不是子shell内插值。

相反,将任何涉及子shell的行放入使用单引号定义的变量中,然后再插入该变量。

autoload -U colors && colors

local parse_special='%{$fg[yellow]%}$(date)%{$reset_color%}'

PS1="%{$fg[green]%}%n@%m %{$fg[blue]%}%c ${parse_special} %# "

更新:根据ZyX的回答,为了完整解决此问题,您还需要添加以下内容:

setopt promptsubst

事实上,我建议像这样将您提示的每个部分提取到一个变量中,包括在每个变量中重置颜色。这样做可以让您更改提示组件的顺序而不更改其实现。


感谢您的回复。我觉得这是正确的解决方案,但我仍然可能做错了什么(请参见我对原始帖子所做的编辑)。似乎我不能在这里使用单引号。另外,您能解释一下为什么在您的回复中使用单引号很重要吗? var =“ $(do_stuff)”是否与var ='$(do_stuff)'有所不同? - D.C.
尝试移除子shell周围的%{%}符号。我不知道为什么,但是它对我来说在没有这些符号的情况下可以工作。单引号和双引号之间的区别在于shell执行插值的方式。var =“$(do_stuff)”立即执行子shell并插入结果一次。当您使用单引号时,该子shell不会被解释,并保持为文本常量,直到它与双引号字符串插值在一起时才会被执行。然后它被执行。基本上,它等待提示刷新以执行子shell。 - cjhveal
2
@cjhveal %{ %} 将文本括起来,告诉 zsh 应该将其视为零宽度(通常是一些序列,告诉终端对接下来的文本进行某些操作,如更改其颜色)。如果你在其中括起非零宽度的文本,它仍然会被显示出来,但会出现许多错误(例如,当你完成时,zsh 告诉终端它想要光标在某个位置并在那里放置文本。%{非零宽度文本%} 会使这个位置错误,并且你会得到覆盖提示符并以提示符颜色着色的文本)。 - ZyX
1
请参考ZyX的答案,我错过了“setopt promptsubst”这个关键部分。还可以参考https://dev59.com/rWfWa4cB1Zd3GeqPdhh9来完成此循环。 - D.C.
我找到问题了,它是由于双引号导致的。使用单引号就可以正常工作。所以应该是PS1='......' - Muhammad Umer
从双引号切换到单引号解决了我在git分支未在提示符中更改的类似问题。谢谢! - Tao Starbow

12

你已经完成了解决这个问题的一半:

PS1='$(date)'

将会显示一个提示$(date),但是

PS1='$(date)'
setopt promptsubst

这将显示提示符 Thu Aug 9 21:01:53 MSK 2012 (当然,这取决于$LANG$LC_TIME)。

顺便说一下,在最新版的zsh中,您不再需要使用%{$fg[blue]%},而是使用%F{blue}来设置前景色,使用%K{blue}来设置背景色,使用%f%k来重置它们以及其他一些内容。请参见man zshmisc,第EXPANSION OF PROMPT SEQUENCES部分。


啊,是的,设置 setopt promptsubst 就是我缺失的一部分。非常感谢。我要编辑上面的回答,添加那一行,以便将这两个答案合并成一个完整的答案。再次感谢。 - D.C.

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