Bash – How to Start XTerm with Prompt at the Bottom

bashterminalxterm

When starting XTerm the prompt starts at the first line of the terminal. When running commands the prompt moves down until it reaches the bottom, and from then on it stays there (not even ShiftPage Down or the mouse can change this). Rather than have the start of the terminal lifetime be "special" the prompt should always be at the bottom of the terminal. Please note that I have a multi-line prompt.

Of course, it should otherwise work as before (resizeable, scrollable, no unnecessary newlines in the output, and no output mysteriously disappearing), so PROMPT_COMMAND='echo;echo;...' or similar is not an option. The solution ideally should not be shell-specific.

Edit: The current solution, while working in simple cases, has a few issues:

  • It's Bash specific. An ideal solution should be portable to other shells.
  • It fails if other processes modify PS1. One example is virtualenv, which adds (virtualenv) at the start of PS1, which then always disappears just above the fold.
  • Ctrll now removes the last page of history.

Is there a way to avoid these issues, short of forking XTerm?

Best Answer

If using bash, the following should do the trick:

TOLASTLINE=$(tput cup "$LINES")
PS1="\[$TOLASTLINE\]$PS1"

Or (less efficient as it runs one tput command before each prompt, but works after the terminal window has been resized):

PS1='\[$(tput cup "$LINES")\]'$PS1

To prevent tput from changing the exit code, you can explicitly save and reset it:

PS1='\[$(retval=$?;tput cup "$LINES";exit $retval)\]'$PS1

Note that the variable retval is local; it doesn't affect any retval variable you might have defined otherwise in the shell.

Since most terminals cup capability is the same \e[y;xH, you could also hardcode it:

PS1='\[\e[$LINES;1H\]'$PS1

If you want it to be safe against later resetting of PS1, you can also utilize the PROMPT_COMMAND variable. If set, it is run as command before the prompt is output. So the effect can also be achieved by

PROMPT_COMMAND='(retval=$?;tput cup "$LINES";exit $retval)'

Of course, while resetting PS1 won't affect this, some other software might also change PROMPT_COMMAND.

Related Question