1

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?

3 Answers 3

3

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)\[$RESET\]\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
6
  • What's the advantage of using $PROMPT_COMMAND to set $PS1 instead of just having a dynamic $PS1 string? Sep 18, 2012 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, 2012 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, 2012 at 5:00
  • Thanks; I wasn't aware of $PROMPT_COMMAND, so that's good to know! Sep 20, 2012 at 9:54
  • 1
    I think you mean $RESET instead of $OFF in the last line.
    – onlycparra
    Jun 23, 2023 at 10:41
1

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\]\$
1
  • 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? Sep 17, 2012 at 21:05
0

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.

0

You must log in to answer this question.

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