Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

As others have pointed out, color codes in PS1 should be bracketed by \[ and \] to avoid them taking up horizontal space. I've added the necessary code to .bashrc:

highlight()
{
    if [ -x /usr/bin/tput ]
    then
        printf '\['
        tput bold
        printf '\]'
        printf '\['
        tput setaf $1
        printf '\]'
    fi
    shift
    printf -- "$@"
    if [ -x /usr/bin/tput ]
    then
        printf '\['
        tput sgr0
        printf '\]'
    fi
}

highlight_error()
{
    highlight 1 "$@"
}

The last function is used in PS1 in both normal and escaped command substitutions to be able to change the string based on the result of the previous command:

# Exit code
PS1="\$(exit_code=\${?#0}
highlight_error \"\${exit_code}\${exit_code:+ }\")"

...

if [ "$USER" == 'root' ]
then
    PS1="${PS1}$(highlight_error '\u')"
else
    PS1="${PS1}\u"
fi

The issue is then that the escaped brackets are output as literals, so my prompt looks like this after running a command which doesn't exist:

\[\]\[\]127 \[\]user@machine:/path
$

Wrapping the escaped highlight_error in printf %b didn't help. How can I fix the output so that I can use the functions for both normal and escaped command substitutions?

share|improve this question
add comment

1 Answer

up vote 3 down vote accepted

It seems that any escape sequence actually in PS1 literally needs to be wrapped in \[ and \], but if you call a function or command that produces output, it does not need to be wrapped.

So why not just move the

"\$(exit_code=\${?#0}
highlight_error \"\${exit_code}\${exit_code:+ }\")"

stuff inside a function, e.g.

print_error_if_error()
{
    exit_code=$?
    if [ $exit_code -ne 0 ]; then
        highlight_error "$exit_code "
    fi
}

and then I think you can remove all the \[ and \] stuff...

highlight()
{
    if [ -x /usr/bin/tput ]
    then
        tput bold
        tput setaf $1
    fi
    shift
    printf -- "$@"
    if [ -x /usr/bin/tput ]
    then
        tput sgr0
    fi
}

highlight_error()
{
    highlight 1 "$@"
}

PS1='$(print_error_if_error)'

# ...

if [ "$USER" = 'root' ]
then
    PS1="${PS1}$(highlight_error '\u')"
else
    PS1="${PS1}\u"
fi
share|improve this answer
    
Aha, that explains why it's been working so far. Thanks! –  l0b0 Apr 12 '11 at 11:10
    
Ouch, turns out this only works because of the \n in my PS1. If I remove it my input will overlap like before :( –  l0b0 Jul 8 '11 at 9:09
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.