7

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);
  • You need to include the conditions in the PS1 (e.g. using `$(...)`). – choroba Jul 21 '19 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 '19 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 '19 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 '19 at 14:51

2 Answers2

14
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.)

ilkkachu
  • 133,243
  • 15
  • 236
  • 397
5

Use the quotes.

PS1='$(displayPS1)'

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

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
ctrl-alt-delor
  • 27,473
  • 9
  • 58
  • 102
  • It won't work, since it will escape the colors – Mr. Madamin Jul 21 '19 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 '19 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 '19 at 15:15
  • @ilkkachu Fair enough. You're talking the the guy who uses `$` for prompt :-) – Kusalananda Jul 21 '19 at 15:19
  • @Kusalananda, colors are optional, but I couldn't live without the working directory being included in the prompt... – ilkkachu Jul 21 '19 at 15:20
  • What's wrong with `$` for prompt ? :) @ilkkachu – Mr. Madamin Jul 21 '19 at 15:39
  • I used single quote inside in order to re-evaluate commands like node and git, and left colors separately. I found this solution on the web, as you can see, I'm a beginner in shell @Kusalananda – Mr. Madamin Jul 21 '19 at 15:41