2

For linux machines I can use:

# vi ~/.bashrc # red/green terminal colors regarding exit code

export PROMPT_COMMAND='PS1="`
if [[ \$? = "0" ]];
then echo "\\[\\033[0;32m\\]";
else echo "\\[\\033[0;31m\\]";
fi`[\u@\h \w]\[\e[m\] "'
export PS1

to get green terminal when exit code is 0, and get red prompt when exit code is not 0.

How can I do this under OpenBSD? (the default ksh)

(I was trying to do it, but with no luck - using ssh to connect to the OpenBSD machine from my notebook - ubuntu/gnome-terminal. )

1
  • 2
    Typically, PS1 does not need to be exported since I don't know of any programs besides interactive shells that use it, and interactive shells get their value of PS1 from the relevant rc file already. The reason I mention this is environment variables take up space in ARG_MAX which means you generally don't want a huge environment, or else you will run into "argument list too long" errors more frequently.
    – jw013
    May 7, 2012 at 1:08

2 Answers 2

4

Each shell has its own way of expanding the prompt. OpenBSD's ksh is pdksh. See its prompt settings in the manual, under the PS1 parameter.

The way ksh works is that it performs parameter substitution, command substitution and arithmetic substitution (all the $ expansions) on the value of PS1 before printing the prompt. So you set PS1 once and for all, but the value is regenerated each time. (You can do that in bash too, if you put shopt -s promptvars in your .bashrc.)

OpenBSD's ksh supports backslash escapes similar to bash. With other versions of ksh, you'd need to translate the bash prompt escape sequences into $ substitutions as well.

PS1='$(if (($? == 0)); then print -n "\\033[32m"; else print -n "\\033[31m"; fi)'
PS1="$PS1"'[\u@\h \w]'$(print '\033')'[0m '

The simple translation above has a few defects:

  • It forks a process each time, to analyze $?. There is a way to avoid this, but it's hackish in ksh88.
  • It causes redrawing bugs, because of the zero-width control sequences. This can be avoided with the gross hack documented in the manual.

Here's some more complex code that uses arithmetic to avoid spawning a subshell and takes care of delimiting non-printable sequences.

escape=$(print '\033')
ctrla=$(print '\001')
PS1=$(print '\001\015')
PS1=$PS1$ctrla$escape'[$(($? ? 31 : 32))m'$ctrla
PS1=$PS1'[\u@\h \w]'
PS1=$PS1$ctrla$escape'[0m'$ctrla' '
3

The problem is only bash has PROMPT_COMMAND. Try this instead:

PS1='\[$(if (($?)); then tput setaf 1; else tput setaf 2; fi)\]'\
'[\u@\h \w]\['"$(tput sgr0)"'\]'

¹ Caveat: I haven't tested this on ksh, but it avoids PROMPT_COMMAND and works in bash.

² tput uses your system's terminfo databases. This is generally more portable and maintainable than hard-coding escape sequences, provided terminfo is installed correctly.

2
  • tput: Unknown terminfo capability "2" when I log in via console:P May 7, 2012 at 2:31
  • 2
    You need to set TERM to something that supports the setaf attribute, e.g. TERM=xterm. (I think the error indicates tput doesn't know that setaf takes a numeric argument, since it's not set for your current terminal.)
    – Mikel
    May 7, 2012 at 3:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .