Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Clarification: I want __foo to be executed each time the PS1 string is presented in the terminal, not when the PS1 string is constructed (hence its being in quotes). __foo contains logic that examines the current directory, so its execution must be deferred.


I'm trying to use different colours in my Bash PS1 string from within a Bash function:

LIGHTRED="\033[1;31m"
LIGHTGREEN="\033[1;32m"
RESET="\033[m"

__foo () {
    # Do some stuff and genereate a string to echo in different colours:
    echo -n '\['$1'\]firstcolour \['$2'\]secondcolour'
}

PS1='$(__foo '$LIGHTRED' '$LIGHTGREEN')\['$RESET'\] \$'

Essentially I want __foo to generate part of the PS1 in a bunch of different colours. My attempt doesn't seem to work, though; it produces the following output:

-bash: 31m: command not found
-bash: 32m: command not found
\[]firstcolour \[\]secondcolour $

What gives, and how can I fix it?

share|improve this question
up vote 2 down vote accepted

Use the Bash environment variable $PROMPT_COMMAND to redefine the $PS1 variable just before the prompt is displayed.

LIGHTRED='\033[1;31m'
LIGHTGREEN='\033[1;32m'
RESET='\033[m'

__foo () {
  # Do some stuff and genereate a string to echo in different colours:
  echo -n "\[$1\]firstcolour \[$2\]secondcolour"
}

PROMPT_COMMAND=$PROMPT_COMMAND'; PS1="$(__foo $RED $GRN)\[$OFF\]\n\$ "'

Note two additional changes that I have made to your code are optional here. They were added because I think it clarifies where/where not the escape codes get expanded:

  • Hard quotes ' around the color definition variables.
  • Soft quotes " around the return string for __foo
share|improve this answer
    
What's the advantage of using $PROMPT_COMMAND to set $PS1 instead of just having a dynamic $PS1 string? – Will Vousden Sep 18 '12 at 9:51
    
I think the quoting is easier using PROMPT_COMMAND; you don't need to create a string that runs a command every time it is evaluated; you just evaluate the dynamic parts and put the result in PS1. – chepner Sep 19 '12 at 19:09
    
@WillVousden -- Zero advantage. It is just an answer that will work. I provided this one because I guessed no one else would suggest solving the question with this approach. – zero2cx Sep 20 '12 at 5:00
    
Thanks; I wasn't aware of $PROMPT_COMMAND, so that's good to know! – Will Vousden Sep 20 '12 at 9:54

Your function foo returns a string which is executed by bash as a command, since you surrounded it with $() (and escaped all variable substitution with single quote marks.

Changing your code to this make it work just fine:

LIGHTRED="\033[1;31m"
LIGHTGREEN="\033[1;32m"
RESET="\033[m"

__foo () {
  # Do some stuff and genereate a string to echo in different colours:
  echo -n '\['$1'\]firstcolour \['$2'\]secondcolour'
}

PS1=$(__foo $LIGHTRED $LIGHTGREEN)\[$RESET\]\$
share|improve this answer
    
I should've been clearer in my question: I want __foo to be executed each time the PS1 string is presented at the terminal, not when the script is executed. I've updated my question. How can I do this? – Will Vousden Sep 17 '12 at 21:05

I've solved it:

LIGHTRED="\033[1;31m"
LIGHTGREEN="\033[1;32m"
RESET="\033[m"

__foo () {
    # Do some stuff and genereate a string to echo in different colours:
    echo -n '\['$1'\]firstcolour \['$2'\]secondcolour'
}

PS1='$(__foo "'$LIGHTRED'" "'$LIGHTGREEN'")\['$RESET'\] \$'

The arguments to __foo needed to be enclosed in quotes.

share|improve this answer

You must log in to answer this question.

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