182

I've noticed this on occasion with a variety of applications. I've often thought it was because the output was cancelled early (ctrl+c, for example) or something similar, and zsh is filling in a new line character. But now curiosity has gotten the best of me, since it doesn't seem to do this in bash.

zsh

zsh

bash

enter image description here

The Sequence program is something I pulled from a book while reading on Java certifications and just wanted to see if it would compile and run. I did notice that it does not use the println() method from the System.out package/class. Instead it uses plain old print().

Is the lack of a new line character the reason I get this symbol?

jktravis
  • 2,216

3 Answers3

162

Yes, this happens because it is a "partial line". And by default zsh goes to the next line to avoid covering it with the prompt.

When a partial line is preserved, by default you will see an inverse+bold character at the end of the partial line: a "%" for a normal user or a "#" for root. If set, the shell parameter PROMPT_EOL_MARK can be used to customize how the end of partial lines are shown.

Leiaz
  • 4,462
  • 1
  • 25
  • 14
60

That's a specific feature of zsh (and now fish as well) to let you clearly see unterminated lines in a command's output.

In traditional shells, if a command outputs some data after the last newline character, or, in other words, if it leaves the terminal cursor not at the start of the line, the next prompt by the shell ends up appended to that last unterminated line as in:

bash-4.4$ printf XXX
XXXbash-4.4$

That mangles the prompt, and it's easy to miss that XXX there especially if you've got a fancier prompt than that. It also affects cursor positioning which causes display glitches when you move the cursor around.

zsh works around that, by showing that the output has an unterminated line with a % character in bold and reverse video, and issues the next prompt at the beginning of the next line:

zsh-5.1.1$ printf XXX
XXX%
zsh-5.1.1$

It does that by outputting that reverse video % at the end of every command (before each prompt), but followed by 79 spaces (assuming a 80 character wide terminal), a CR character (the one that causes the cursor to go back to the first column) and the sequence to erase to the end of the line (and then the prompt).

That way, if there was an unterminated line, since the cursor is not in first position, those 80 characters will make the cursor move to the next line (and that % will stay). If not, then that % and those 79 spaces will be on a one line which will be deleted afterwards.

Now, that only works if the terminal does wrap lines (for instance, that won't work properly after tput rmam). If you have a slow terminal (like on 9600 baud serial line), you may actually see those % being displayed and then removed after each command, so zsh lets you disable that feature:

set +o prompt_cr +o prompt_sp

That way, zsh behaves more like traditional shells.

You can also change that mark with the $PROMPT_EOL_MARK variable.

12

Explanation:

The percentage sign (%) at the end of a line indicates a missing newline character (\n).

For example, printf "foo" results in foo%. Adding a newline character to the string, printf "foo\n", results in foo.

How to remove a percentage sign(%):

To remove the percentage sign, append your code with ; echo.

Example:

# Issue
$ print -n "foo"
foo%

Solution

$ print -n "foo"; echo foo