2014-01-26 80 views
2

我注意到在this video,终端提示扩展终端的整个宽度,然后分解到一个新的行。我如何设置我的PS1变量来填充剩余的终端空间中的某个角色,就像这个用户所做的那样?如何让我的终端提示扩展终端的宽度?

问题是,我不知道如何更新每个命令的PS1变量。在我看来,PS1的字符串值只能被读入一次,因为.bashrc文件只被读入一次。在每个命令或其他东西之后,我是否必须编写某种钩子?

我还应该指出,PS1变量将根据组成它的转义字符评估到不同的长度。例如,打印路径为\w

我知道我可以使用$(COLUMNS)终端宽度,以及当前PS1变量与${#PS1}宽度,做数学题,并打印的字符缓冲区适量的,但我怎么得到它更新每次。有没有一种首选方式?

回答

1

使用PROMPT_COMMAND在每个命令前重置PS1的值。

PROMPT_COMMAND=set_prompt 
set_prompt() { 
    PS1=... 
} 

虽然一些系统脚本(或你自己)可能已经在使用PROMPT_COMMAND的东西,在这种情况下,你可以简单地添加到它。

PROMPT_COMMAND="$PROMPT_COMMAND; set_prompt" 
2

让我们假设你希望你的提示是这个样子:

left text----------------------------------------------------------right text 
prompt$ 

这是相当直接的规定,right text具有已知大小。 (例如,它可能是当前的日期和时间。)我们所做的是打印正确数量的破折号(或者,对于utf-8终端,更漂亮的\u2500),然后是right text,然后回车(\r不是一个换行符)和左边的文字,它会覆盖破折号。唯一棘手的一点是“正确的破折号”,但我们可以使用$(tput cols)来查看终端的宽度,幸运的是bash将命令展开PS1。因此,例如:

PS1='\[$(printf "%*s" $(($(tput cols)-20)) "" | sed "s/ /-/g") \d \t\r\[email protected]\h:\w \]\n\$ ' 

这里,$(($(tput cols)-20))是终端减去20,其是基于\d \t宽确切地说是20个字符(包括初始的空间)的宽度。

PS1不理解utf-8转义(\uxxxx),并且在sed命令中插入适当的替换会涉及恼人的嵌入引号问题,虽然这是可能的。然而,printf不明白UTF-8逃逸,所以更容易产生以不同的方式划线的序列:

PS1='\[$(printf "\\u2500%.0s" $(seq 21 $(tput cols))) \d \t\r\[email protected]\h:\w \]\n\$ ' 

另一种方式来做到这涉及关闭终端的autowrap,这是可能的,如果你正在使用xterm或实现相同控制代码(或Linux控制台本身)的终端仿真程序。要禁用自动换行,输出序列ESC[l。要打开它,请使用ESC[h。禁用自动换行功能后,一旦输出到达行尾,最后一个字符将被下一个字符覆盖,而不是开始新行。使用这种技术,计算虚线序列的确切长度并不是必须的。我们只需要破折号的字符串,它的长度超过任何控制台将广,说以下内容:

DASHES="$(printf '\u2500%0.s' {1..1000})" 
PS1='\[\e[?7l\[email protected]\h:\w $DASHES \e[19D \d \t\e[?7h\]\n\$ ' 

这里,\e[19D是“移动光标倒退19个字符的”终端仿真程序代码。我本可以用$(tput cub 19)代替。 (可能有一个tput参数用于打开和关闭自动包装,但我不知道它会是什么。)

视频中的示例还涉及在实际命令行中插入右对齐的字符串。我不知道用bash这样做的任何干净的方式;视频中的控制台几乎肯定使用zshRPROMPT功能。当然,您可以使用上述相同的技术在bash中输出右对齐提示,但readline不会知道任何有关它们的信息,因此只要您执行某些操作来编辑该行,正确的提示就会消失。