251

I have an issue where if I type in very long commands in bash the terminal will not render what I'm typing correctly. I'd expect that if I had a command like the following:

username@someserver ~/somepath $ ssh -i /path/to/private/key
[email protected]

The command should render on two lines. Instead it will often wrap around and start writing over the top of my prompt, somewhat like this:

[email protected] -i /path/to/private/key

If I decide to go back and change some argument there's no telling where the cursor will show up, sometimes in the middle of the prompt, but usually on the line above where I'm typing.

Additional fun happens when when I Up to a previous command. I've tried this in both gnome-terminal and terminator and on i3 and Cinnamon. Someone suggested it was my prompt, so here that is:

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

Ctrll, reset, and clear all do what they say, but when I type the command back in or Up the same things happens.

I checked and checkwinsize is enabled in bash. This happens on 80x24 and other window sizes.

Is this just something I learn to live with? Is there some piece of magic which I should know? I've settled for just using a really short prompt, but that doesn't fix the issue.

6
  • 2
    So using the command env -i bash --norc fixes it. The $COLUMNS and $LINES match. Does that mean that there's something funny with my .bashrc?
    – Muricula
    Commented Dec 20, 2013 at 0:44
  • 1
    So I commented out my .bashrc and wound up isolating my prompt as the problematic part, specifically the coloration syntax involved. What's wrong with the PS1 above?
    – Muricula
    Commented Dec 20, 2013 at 0:53
  • 1
    \[\033[01;32m\]\u: \[\033[01;34m\]\W \[\033[01;34m\] \$ \[\033[0m\] seems to avoid the weirdness in the behavior - but don't know if it respects your original prompt completely...
    – user44370
    Commented Dec 20, 2013 at 1:19
  • 3
    As per this answer on serverfault, use tput smam
    – Samveen
    Commented Oct 23, 2017 at 10:38
  • set term=XTERM worked for me
    – Tinmarino
    Commented Jan 8, 2021 at 16:52

11 Answers 11

286

Non-printable sequences should be enclosed in \[ and \]. Looking at your PS1 it has a unenclosed sequence after \W. But, the second entry is redundant as well as it repeats the previous statement "1;34".

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

As such this should have intended coloring:

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

Keeping the "original" this should also work:

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

Edit:

The reason for the behavior is because bash believes the prompt is longer then it actually is. As a simple example, if one use:

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

The prompt is believed to be 8 characters and not 1. As such if terminal window is 20 columns, after typing 12 characters, it is believed to be 20 and wraps around. This is also evident if one then try to do backspace or Ctrl+u. It stops at column 9.

However it also does not start new line unless one are on last column, as a result the first line is overwritten.

If one keep typing the line should wrap to next line after 32 characters.

9
  • If you have - or anyone - has an explanation as to what exactly in the original sequence caused the line to repeat over itself, I'd be interested in knowing that. Also +1 for how you showed this visually.
    – user44370
    Commented Dec 20, 2013 at 2:42
  • 1
    @illuminÉ: Have not looked at the source, but added an update with a note on behavior from observation.
    – Runium
    Commented Dec 20, 2013 at 3:26
  • Just in case you are facing any problems, you can use this website to create a new one - bashrcgenerator.com Commented Dec 11, 2015 at 6:12
  • 3
    @nycynik: Observation. I guess the closest to documentation on this is the source code ...
    – Runium
    Commented Mar 30, 2017 at 21:17
  • 6
    Not all heroes wear capes. Commented Aug 29, 2019 at 13:40
105

It is mostly to do with the size of the window assumed by the terminal is not the same as your actual window size. If you are using bash, you can try this.

$ shopt checkwinsize

If you don't get

checkwinsize    on

Then activate it with

$ shopt -s checkwinsize

Then just attempt running another command (like ls) or resizing the window once, the above works for me every time.

For Redhat systems particularly, the issue is often caused by misconfiguring ~/.bashrc not to call /etc/bashrc. Normally, bash loads ~/.bashrc which is expected to call /etc/bashrc, which by default contains shopt -s checkwinsize.

6
  • Had the same problem with OS X, apparently if you call "login" to start your terminal, it starts bash in a way that reads /etc/bashrc, but if you just call straight to bash, the ~/.bashrc doesn't source things by default so you get the odd wrapping effect. Thanks!
    – rogerdpack
    Commented Sep 11, 2015 at 22:16
  • 1
    This worked for me as well. Colors were not on in this particular server, calling correct /etc/bashrc, everything else was good to go...turns out this is the cause of the wrapping issues.
    – dhaupin
    Commented Nov 20, 2015 at 20:23
  • See also unix.stackexchange.com/a/61608/2221
    – user2221
    Commented May 4, 2016 at 10:17
  • 1
    Looks like a good solution. But it doesn't work in my ssh session, though. Not sure why. I have run the command shopt -s checkwinsize in the ssh session. But the wrapping persists.
    – Qiang Xu
    Commented Jul 20, 2018 at 19:15
  • This was precisely my problem - a user .bashrc wasn't calling /etc/bashrc, and so making a mess.
    – Sobrique
    Commented Aug 15, 2019 at 9:14
33

I once read somewhere (don't know where anymore) that using \001 and \002 instead of \[ and \] can solve this issue. It did for me.

By the way, defining PS1 does not have to look ugly.

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
3
  • 6
    My PS1 calls a command that printf escape sequences causing OP's problem. Only this solution fixes the issue for me. Commented Jun 4, 2018 at 6:47
  • 1
    exactly what I was looking for to put in my inpurc set vi-ins-mode-string "${green}I ${white}|"
    – rambi
    Commented Dec 20, 2021 at 12:25
  • 1
    this worked for me and it's pretty elegant as well Commented Jun 9, 2022 at 2:16
14

As mentioned in other answers, non-printable sequences such as \e[0;30m should be wrapped with \[...\].

Additionally (and what I don't see mentioned yet) is it seems that \r\n should be outside of the \[...\] if you have a multi-line prompt. It took me some of trial and error to finally figure that out.

1
  • Exactly what I needed.
    – Lazik
    Commented Feb 11, 2023 at 15:34
12

This sounds like an issue with your COLUMNS & LINES environment variable settings. When you resize the window they're typically set automatically by gnome-terminal (I believe) you can force them to be manually set by issuing the command resize.

Example

If I resize my gnome-terminal to 79x17 my variables show up like so:

$ echo $COLUMNS; echo $LINES
79
17

I can force it like so:

$ resize
COLUMNS=79;
LINES=17;
export COLUMNS LINES;
4
  • 1
    Interesting, but doesn't help.
    – Muricula
    Commented Dec 19, 2013 at 22:57
  • 1
    This fixed my issue it was not wrapping lines correctly after I ran the command "screen". Thanks!!
    – nukeguy
    Commented May 30, 2017 at 20:21
  • What package does the command resize come from?
    – till
    Commented Mar 8, 2020 at 12:22
  • @till - think it's part of X11 - kb.iu.edu/d/abwh
    – slm
    Commented Mar 9, 2020 at 15:40
9

To prevent wrapping, you can also increase the number of columns using, e.g.

stty columns 120
2
6

Also the same issue can be caused by using wide unicode symbols (like from https://stackoverflow.com/a/34812608/1657819). Here is the snippet causing the problem (mind the $Green and $Red are properly escaped color strings):

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 cannot calculate the length correctly, so easiest way could be to escape 2 out of three parts of those wide symbols.

FancyX='\[\342\234\]\227'
Checkmark='\[\342\234\]\223'
3
  • Makes sense. What I guess is that bash counts characters. Because the X takes one char but is written as 3, then one needs to enclose 2 of them to fix counting. @blauhirn answer also explains how to do in a function with \001 and \002. Commented Jan 24, 2019 at 22:59
  • FYI, this is how you figure out how to output multi-byte unicode characters in this format: stackoverflow.com/a/602924/520567 Commented Jan 25, 2019 at 7:36
  • If you get your prompt set up correctly, you might also see these symptoms if there's a mismatch between bash and your terminal. For example, I had changed my LANG variable from the default of en_US.utf8 to en_US.iso88591 in order to work on some data in the Latin-1 character set, and I had forgotten to change it back when I was done. Commented May 6, 2021 at 21:28
4

tput smam

On Ubuntu 19.10 in a Gnome terminal, which has TERM=xterm-256color, this emits the exact escape sequence that makes the terminal wrap lines:

tput smam

You can see what that escape is with:

tput smam | hd

Resetting the terminal state with:

reset

also seems to have the effect of setting tput smam.

The man page:

man terminfo

documents smam and its opposite rmam:

       enter_am_mode   smam   SA   turn on automatic margins
       exit_am_mode    rmam   RA   turn off automatic margins

Note however that certain terminals don't have that capability, e.g. inside tmux we have TERM=screen-265color and smam does not appear on the list of capabilities:

infocmp

and so tput smam doesn't print anything.

I'm not sure how, but QEMU was able to change the line wrap state of tmux while tput wasn't.

3
  • 3
    Under tmux and screen, setterm --linewrap=off still works. Probably hard-coded to \033[?7l and \033[?7h without consulting termcap/terminfo? Commented Oct 21, 2020 at 21:22
  • @BeniCherniavsky-Paskin thanks for this info. I'm going to try it out next time it starts hurting me! :-) Gotta (re)learn where the escape code list is documented. Commented Oct 21, 2020 at 21:28
  • @BeniCherniavsky-Paskin OK, Esc[?7l is what it emits according to hd and its name is DECAWM according to ascii-table.com/ansi-escape-sequences-vt-100.php Commented Oct 21, 2020 at 21:32
2

I have 2 almost identical Archlinux setups and after I switched one to "powerline" PS1 with Unicode characters I've got the same problem. It turned out that on affected laptop I was missing /etc/locale.conf file

LANG=en_US.UTF-8
LANGUAGE=en_US.UTF-8
LC_COLLATE=en_US.UTF-8

once I've copied it over, terminal became Unicode-aware and "line overlap" problem went away.

1
  • This answer saved me. I had totally forgotten that I had put LC_ALL=C in my .bashrc. With Starship, this was causing prompt issues. Switching to UTF-8 (which is what I should have used in the FIRST place) fixed my problem. Commented Jan 23, 2023 at 17:08
0

Thanks to this article, I've got my prompt working very nicely. And when combined with gitprompt (https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh), I get the exact things I want.

PS1_RESET='\001$(tput sgr0)\002'
PS1_ERROR='$(code=${?##0};echo ${code:+\001$(tput setaf 1)\002[${code}]\ })'"$PS1_RESET"
PS1_SHLVL='\001$(tput setaf 4)\002($SHLVL) '"$PS1_RESET"
PS1_DATE='\001$(tput setaf 5)\002\D{%Y-%m-%d %H:%M:%S} '"$PS1_RESET"
PS1_USER='\001$(tput setaf 6)\002\u'"$PS1_RESET"
PS1_AT='\001$(tput sgr0)\002@'"$PS1_RESET"
PS1_HOST='\001$(tput setaf 2)\002\h'"$PS1_RESET"
PS1_COLON='\001$(tput sgr0)\002:'"$PS1_RESET"
PS1_PATH='\001$(tput setaf 3)\002\w'"$PS1_RESET"
PS1_GIT='$(__git_ps1 " (%s)")'"$PS1_RESET"
PS1_PROMPT=' \\$ '
PS1_COMBINED=$PS1_ERROR$PS1_SHLVL$PS1_DATE$PS1_USER$PS1_AT$PS1_HOST$PS1_COLON$PS1_PATH
export PS1="$PS1_COMBINED"

GIT_PS1_COMPRESSSPARSESTATE=
GIT_PS1_DESCRIBE_STYLE=
GIT_PS1_HIDE_IF_PWD_IGNORED=yes
GIT_PS1_OMITSPARSESTATE=
GIT_PS1_SHOWCOLORHINTS=yes
GIT_PS1_SHOWDIRTYSTATE=yes
GIT_PS1_SHOWSTASHSTATE=yes
GIT_PS1_SHOWUNTRACKEDFILES=yes
GIT_PS1_SHOWUPSTREAM="auto"
GIT_PS1_STATESEPARATOR=" "
export PROMPT_COMMAND='__git_ps1 "$PS1_COMBINED" "$PS1_PROMPT"'
0

The question asked is for the Bash shell interpreter, as like many of the other questions on similar topic. None, if not few, point to on how to do it on the Zsh shell interpreter.

\[ ... \] or \001 ... \002 won't work with .zshrc. For Zsh, the special characters are %{ and %}. For example, here is how you would configure your prompt with colors in .zshrc :

promptText="megh$ "
PS1="%{$(tput bold)$(tput setaf 3)%}$promptText%{$(tput sgr0)%}"

Link to documentation

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.