终端提示未正确包装


170

我有一个问题,如果我在bash中输入很长的命令,终端将无法正确显示我键入的内容。我希望如果我有如下命令:

username@someserver ~/somepath $ ssh -i /path/to/private/key
myusername@something.someserver.com

该命令应在两行上呈现。相反,它通常会环绕起来并开始在提示的顶部进行书写,如下所示:

myreallylongusername@something.somelongserver.comh -i /path/to/private/key

如果我决定返回并更改一些参数,则无法确定光标将出现在哪里,有时在提示的中间,但通常在我键入的位置的那一行

当我Up执行上一个命令时,会带来更多乐趣。我已经在gnome-terminal和Terminator以及i3和Cinnamon上进行了尝试。有人建议这是我的提示,所以这里是:

\[\033[01;32m\]\u:\[\033[01;34m\] \W\033[01;34m \$\[\033[00m\]

Ctrll,,resetclear都按照他们说的去做,但是当我重新输入命令时,还是Up发生了同样的事情。

我检查并checkwinsize启用了bash。这发生在80x24和其他窗口尺寸上。

这只是我学会生活的东西吗?我应该知道一些魔术吗?我已经同意只使用一个很短的提示,但这不能解决问题。


1
因此,使用该命令可以env -i bash --norc修复该问题。$ COLUMNS和$ LINES匹配。这是否意味着我的.bashrc有一些有趣的事情?
Muricula

因此,我注释掉了.bashrc并结束了将提示隔离为有问题的部分,特别是涉及的着色语法。上面的PS1有什么问题?
Muricula 2013年

1
\[\033[01;32m\]\u: \[\033[01;34m\]\W \[\033[01;34m\] \$ \[\033[0m\]似乎避免了行为上的怪异现象-但不知道它是否完全尊重您的原始提示...

1
按照serverfault上的此答案,请使用tput smam
Samveen

Answers:


188

不可打印的序列应包含在\[和中\]。查看您的PS1之后,它有一个未封闭的序列\W。但是,第二个条目是多余的,并且它重复了前面的语句“ 1; 34”

\[\033[01;32m\]\u:\[\033[01;34m\] \W\033[01;34m \$\[\033[00m\]
                  |_____________|               |_|
                         |                       |
                         +--- Let this apply to this as well.

因此,这应该具有预期的颜色:

\[\033[1;32m\]\u:\[\033[1;34m\] \W \$\[\033[0m\]
                               |_____|
                                  |
                                  +---- Bold blue.

保留“原始”内容也应该起作用:

\[\033[1;32m\]\u:\[\033[1;34m\] \W\[\033[1;34m\] \$\[\033[0m\]
                                  |_|         |_|
                                   |           |
                                   +-----------+-- Enclose in \[ \]

编辑:

该行为的原因是因为bash认为提示的时间比实际时间长。举一个简单的例子,如果使用:

PS1="\033[0;34m$"
       1 2345678

该提示被认为是8个字符而不是1。因此,如果终端窗口是20列,则在键入12个字符后,它被认为是20个字符并环绕。如果再尝试退格或,这也很明显Ctrl+u。它停在第9列。

但是,除非在最后一列上,否则它也不会开始新行,因此第一行将被覆盖。

如果继续输入,则该行应在32个字符后换行到下一行。


如果您(或任何人)对原始顺序中的确切原因导致该行在其自身上重复进行了解释,那么我很想知道这一点。此外,您还可以+1以直观的方式展示此内容。

1
@illuminÉ:尚未查看源代码,但添加了更新,并记录了观察到的行为。
Runium

万一您遇到任何问题,可以使用此网站创建一个新网站-bashrcgenerator.com
divinedragon 2015年

太神奇了,谢谢@Runium-您介意分享您的知识吗?我很乐意找到有关此问题的一些文档。
nycynik

2
@nycynik:观察。我猜想最接近文档的是源代码...
Runium

83

这主要与终端假定的窗口大小与您的实际窗口大小不同有关。如果您正在使用bash,则可以尝试此操作。

$ shopt checkwinsize

如果你不明白

checkwinsize    on

然后用

$ shopt -s checkwinsize

然后,只需尝试运行另一个命令(如ls)或调整窗口大小一次,上面的代码对我来说每次都是有用的。

特别是对于Redhat系统,该问题通常是由配置~/.bashrcnot call 引起的/etc/bashrc。通常,bash加载~/.bashrc预期会被调用/etc/bashrc,默认情况下包含shopt -s checkwinsize


在OS X上也有同样的问题,显然如果您调用“登录”来启动终端,它将以读取/ etc / bashrc的方式启动bash,但是如果您直接调用bash,则〜/ .bashrc不会默认情况下提供源内容,因此您会得到奇特的包装效果。谢谢!
rogerdpack 2015年

这也为我工作。颜色不在此特定服务器上,调用正确/etc/bashrc,其他一切都很好...事实证明这是包装问题的原因。
dhaupin 2015年


看起来是一个很好的解决方案。但是,它在我的ssh会话中不起作用。不知道为什么。我已经shopt -s checkwinsize在ssh会话中运行了命令。但是包裹仍然存在。
徐强

这恰好是我的问题-用户.bashrc没有调用/ etc / bashrc,因此一团糟。
Sobrique

9

如其他答案中所述,不可打印的序列(例如)\e[0;30m应使用包裹\[...\]

此外(和我没有看到没有提到)是它似乎\r\n应该是外面\[...\],如果你有一个多行的提示。我花了一些反复试验才能最终弄清楚这一点。


8

有一次,我读的地方(不知道在哪里了),使用\001\002替代的\[\]可以解决这个问题。它对我有用。

顺便说一下,定义PS1不必看起来很丑。

green="\001$(tput setaf 2)\002"
blue="\001$(tput setaf 4)\002"
dim="\001$(tput dim)\002"
reset="\001$(tput sgr0)\002"

PS1="$dim[\t] " # [hh:mm:ss]
PS1+="$green\u@\h" # user@host
PS1+="$blue\w\$$reset " # workingdir$

export PS1
unset green blue dim reset

2
我的PS1调用了一个命令,该命令将printf转义序列引起OP的问题。只有此解决方案可以为我解决此问题。
RickMeasham

6

这听起来像是您的COLUMNSLINES环境变量设置存在问题。调整窗口大小时,通常会通过gnome-terminal自动设置它们(我相信),您可以通过发出命令来强制手动设置它们resize

如果我将gnome终端的大小调整为79x17,则变量将显示如下:

$ echo $COLUMNS; echo $LINES
79
17

我可以这样强制:

$ resize
COLUMNS=79;
LINES=17;
export COLUMNS LINES;

1
有趣,但无济于事。
Muricula 2013年

1
这解决了我的问题,即在我运行“屏幕”命令后无法正确换行。谢谢!!
nukeguy

5

为了防止换行,您还可以使用以下方法增加列数:

stty columns 120

1
这不是一个好主意,它残酷地
破坏

3

同样,使用宽的unicode符号也可能导致相同的问题(例如https://stackoverflow.com/a/34812608/1657819)。这是导致问题的代码段(注意$Green$Red正确地转义了颜色字符串):

FancyX='\342\234\227'
Checkmark='\342\234\223'


# Add a bright white exit status for the last command
PS1="$White\$? "
# If it was successful, print a green check mark. Otherwise, print
# a red X.
if [[ $Last_Command == 0 ]]; then
    PS1+="$Green$Checkmark "
else
    PS1+="$Red$FancyX "
fi

Bash无法正确计算长度,因此最简单的方法可能是将那些宽符号的三部分中的2逸出。

FancyX='\[\342\234\]\227'
Checkmark='\[\342\234\]\223'

说得通。我猜想bash算字符。因为X取一个字符但写为3,所以一个需要将其中2个括起来以固定计数。@blauhirn答案还解释了如何使用\001和进行功能\002
akostadinov

仅供参考,这是您找出如何以这种格式输出多字节unicode字符的方法:stackoverflow.com/a/602924/520567
akostadinov
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.