Dealing with bash breaking commands of a certain length

Use a smarter shell, like zsh:

enter image description here

Note how it added a % to indicate the lack of a newline and printed the prompt on a different line.


Just hit CtrlL. That will redraw your terminal and make everything appear as it should:

enter image description here


This can be done with bash too. The trick is to use a custom PROMPT_COMMAND that queries the terminal for the position of the cursor (as per this question ).

This solution can probably be extended to other shells, but I'm only familiar with bash. (See @muru 's answer for a zsh solution). And perhaps there is already an option in bash to do this automatically.

Put this in your .bashrc:

function new.line.if.not.on.left {
    local foo
    local garbage
    local column
    echo -n -e "\033[6n"     # as the terminal for the position
    read -s -d \[ garbage    # ignore the first part of the response
    read -s -d R foo         # store the position in foo
    column="$(echo "$foo" | cut -d';' -f2)"    # skip over the row number
    test "$column" "!=" 1 && { tput smso; echo "%"; tput rmso; }
}

PROMPT_COMMAND="new.line.if.not.on.left; $PROMPT_COMMAND"

The last line prepends a call to new.line.if.not.on.left to your PROMPT_COMMAND (as you may already have a PROMPT_COMMAND defined).

The bash function new.line.if.not.on.left works as follows:

  • echo -n -e "\033[6n" is a piece of magic that asks the terminal about the row and column of the cursor's current position. The terminal "responds" by sending fake keyboard input with the answer.
  • read -s -d \[ garbage. The first part of the response is some gibberish, some sort of escape code. Ignore it by storing it in garbage.
  • read -s -d R foo . Store the fake keyboard response in bash variable foo. The -s is needed to stop read from echoing the input to the screen again. And -d R is the delimiter - the fake input is terminated by an R, not by a newline as you might expect.
  • column="$(echo "$foo" | cut -d';' -f2)" extracts the column number from the response (i.e. skipping over the row number) and stores the result in column
  • test "$column" "!=" 1 && { tput smso; echo "%"; tput rmso; } If the current column number is not 1, then print the percent sign (and a newline). The tput commands turn on "stand out mode" - which should make the % stand out more - perhaps bold or perhaps by reversing the background and foreground colours.