5

This question already has an answer here:

I'm using a function to dynamically generate output for PS1. There are a couple statements that check if node and package.json exist, and if git and .git folder exist to display node version or the git branch. If none exist it just outputs the User$.

The problem is when user goes into another folder where none of the conditions are met the prompt is not updating. It's like conditions are cached or smth

function displayPS1() {
  MESSAGE="";
  GRAY_BACK="\[\e[100;97m\]";
  GREEN_BACK="\[\e[100;42m\]";
  GREEN_FORE="\[\e[32;1m\]";
  CYAN_BACK="\[\e[100;46m\]";
  CYAN_FORE="\[\e[36;1m\]";
  RESET="\[\e[0m\]";

  if hash node 2>/dev/null && [ -e package.json ]; then
    NODE='$(node -v | sed "s/\(v[0-9]*\)\(\.[0-9]*\.[0-9]*\)/\1/g")';
    MESSAGE="${GRAY_BACK} node ${GREEN_BACK} $NODE ${RESET} User${GREEN_FORE}$ ${RESET}";
  elif hash git 2>/dev/null && [ -d .git ]; then
    BRANCH='$(cat .git/HEAD | sed "s/ref:[[:space:]]refs\/heads\///")';
    MESSAGE="${GRAY_BACK} git ${CYAN_BACK} $BRANCH ${RESET} User${CYAN_FORE}$ ${RESET}";
  else
    MESSAGE="User${CYAN_FORE}$ ${RESET}";
  fi

  echo "$MESSAGE";
}
export PS1=$(displayPS1);

marked as duplicate by muru, terdon bash Jul 23 at 10:51

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • You need to include the conditions in the PS1 (e.g. using $(...)). – choroba Jul 21 at 13:07
  • 1
    Apart from anything else, PS1 really does not need to be exported. It's just the shell using it. Also, running node at least once, possibly twice for each prompt? Would it not be better to overload the cd command? The prompt would not need to be re-evaluated unless you change directory (most of the time at least). – Kusalananda Jul 21 at 14:14
  • I like the idea with the cd. But what if someone removes package.json or node or git, we would need to overload those commands also @Kusalananda – Mr. Madamin Jul 21 at 14:49
  • @Mr.Madamin Um? I'm not sure I follow how that's special if overloading cd? I was thinking something simple, like cd () { builtin cd "$@"; PS1=$(displayPS1); }. – Kusalananda Jul 21 at 14:51
13
export PS1=$(displayPS1);

This will run displayPS1, and the if statements within once, assigning the result to the prompt. The conditions won't be processed again after that.

Instead, put the function call in PROMPT_COMMAND, so it gets called every time the prompt is going to be printed. So either

PROMPT_COMMAND='PS1=$(displayPS1)'

or perhaps rather

PROMPT_COMMAND=setPS1

and make setPS1 a function that sets PS1 itself. (Getting rid of the command substitution saves a fork from the subshell invocation every time the prompt is changed.)

5

Use the quotes.

PS1='$(displayPS1)'

If you don't then the function is evaluated at assignment time.

  • It won't work, since it will escape the colors – Mr. Madamin Jul 21 at 14:46
  • @Mr.Madamin Is that not an issue with your echo at the end of the function (something that would be an issue regardless of when the function is evaluated)? Use echo -e instead of plain echo. You also seem to use single-quoted command substitutions in your code. Why? – Kusalananda Jul 21 at 15:02
  • @Kusalananda, no, because Bash handles backslash-escapes in the prompt. But it does so before processing variable and command substitutions, so putting the function inside one breaks them. In particular, it breaks \[ .. \], since you can't produce them with echo -e or such, they need to be in PS1. – ilkkachu Jul 21 at 15:15
  • @ilkkachu Fair enough. You're talking the the guy who uses $ for prompt :-) – Kusalananda Jul 21 at 15:19
  • @Kusalananda, colors are optional, but I couldn't live without the working directory being included in the prompt... – ilkkachu Jul 21 at 15:20

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