11

Most of the time the output of a command ends with the newline character. But sometimes it does not, so the next shell prompt is printed in the same line together with the output.

Example:

root@hostname [~] # echo -n hello
helloroot@hostname [~] #

I've always found that very annoying.
Now, I could just add a "\n" at the beginning of the the PS1 variable, but most of the time that will print one extra line I dont need.

Is it possible to know whether the last command's output ended with a newline or not?


Solution:
(Thanks to Dennis)

PS1='$(printf "%$((`tput cols`-1))s\r")\u@\h [\w]\$ '
GetFree
  • 1,460
  • 7
  • 23
  • 37
  • This should be moved to superuser. – raphink Dec 27 '09 at 17:42
  • I like your version! You used `$()` in one place and backticks in another. You can use `$()` in both. – Dennis Williamson Dec 29 '09 at 02:08
  • I know. But for me it's easier to read that way – GetFree Dec 29 '09 at 03:26
  • I wouldn't use `tput cols` because it just outputs the value of the COLUMNS variable anyway, and it's slower because it's not a shell builtin. You'll also want to include `\e[K` (equivalent to `tput el`) to delete the inserted whitespace so that you don't get a bunch of trailing whitespace when copying and pasting in the default case. Finally, you need to enclose all this magic between `\[` and `\]` or else bash will try to second-guess your cursor position and it'll mess up when you edit your command/history. – dlitz Jun 14 '19 at 06:35
  • 1
    The whole thing can be done as just: `PS1='\[\e[7m%\e[m$( printf "%*s" "$((COLUMNS-1))" "" )\r\e[K\]\u@\h [\w]\$ '` – dlitz Jun 14 '19 at 06:35

3 Answers3

6

I've been experimenting with the following to emulate the feature from zsh in Bash:

$ unset PROMPT_SP; for ((i = 1; i <= $COLUMNS + 52; i++ )); do PROMPT_SP+=' '; done
$ PS1='\[\e[7m%\e[m\]${PROMPT_SP: -$COLUMNS+1}\015$ '

It issues a reverse video percent sign, followed by a bunch of spaces to make it wrap to the next line, then a carriage return, followed by a dollar sign and a space. You can add prompt escapes after the "\015" to customize your prompt.

Using this depends on how your terminal handles right margin line wrapping (automatic margins). The length of PROMPT_SP is arbitrary, but should be at least 80 or whatever your usual terminal width is. You may need to hard-code that value if $COLUMNS isn't set yet by the time the for loop is run in ~/.bashrc. You may want shopt -s checkwinsize if it's not already set.

Dennis Williamson
  • 60,515
  • 14
  • 113
  • 148
  • I wonder why someone downvoted *each answer*. Hmmm... no explanation. How helpful. – Dennis Williamson Dec 28 '09 at 00:21
  • Here's another way, without using a loop, to create the pad string: `printf -v PROMPT_SP '%*s' $((COLUMNS + 52)) ''` – Dennis Williamson Apr 28 '12 at 00:28
  • What is a "reverse video percent sign"? The word "video" has me confused, and I haven't been able to find the answer on Google. – davidchambers Nov 22 '13 at 23:29
  • 1
    @davidchambers: The background of the character is displayed in the foreground color and the character itself is displayed in the background color. See `man 5 terminfo` and search for "reverse video" to see some documentation that uses this terminology. – Dennis Williamson Nov 22 '13 at 23:56
0

No it isn't possible. Bash itself does not process or see the output of the program it has started.

It just occured to me that it might be possible to write a program to set PROMPT_COMMAND to, which would check the current position of the cursor and issue a newline if the cursor was not at the left edge.

Teddy
  • 5,134
  • 1
  • 22
  • 27
0

zsh tries to solve your problem. If the last output ends without a newline, you will get:

$ echo -n 'abc'
abc%
$ 

Where the % uses inverted background/foreground. Not sure if it's portable to bash in any way.

viraptor
  • 1,264
  • 6
  • 21
  • 40