3

I started tweaking around with my bash prompt lately and I find myself not understanding how the escape character works. I have the following:

PS1="\[$RED\]\342\224\214\342\224\200"

In this I get it, \[ escapes the [ character and \xxx escapes my UTF-8 characters. But in the following line I get a weird result:

PS1+="$([·\$?·!=·0·]·&&·echo·\[$RED\]\342\234\227\·)"

This will always print X in my prompt, yet if I escape the first $ it will print it only when exit status of any command is non zero. I do not understand why. Wasn't $(commands) supposed to output the result of given commands? If I escape it like so \$() is the whole sequence escaped or just the dollar sign? If I don't escape why doesn't it print $? It just prints the X. I have the same question for the $ inside the square brackets. Why do I have to escape it?

Also I believe this qualifies as another question but is there any way of printing the actual exit status in my prompt?

1 Answer 1

2

In a double-quoted string, command substitutions ($(...)) and variable expansions ($foo) are processed, and the backslash in front of the dollar sign prevents that, removing the backslash. This happens during the assignment PS1="$(...)" or PS1="\$(...)".

But the same expansions are also processed when the prompt is printed, so if the dollar sign was escaped on assignment, the resulting PS1 has an unescaped dollar sign, and the expansion happens when the prompt is printed.

So, with an unescaped command substitution, the command only runs once, when the prompt is assigned. With the backslash, it runs every time the prompt is printed.

The difference should be easy to test with these two:

PS1="$(date) "
PS1="\$(date) "

The \[ sequence is different, though. It's only relevant when the prompt is processed, not in regular double-quoted strings. It's used to mark parts of the prompt that don't print any visible characters. Moreover, it only works in the prompt before expansions, so something like PS1='$(echo "\[...\]")' will likely not do what you want.

3
  • Thanks for the explanation. I understand the theory now. I've tried testing with the example you gave but the prompt prints both dates every time instead of two dates when I start the terminal and one after every command. Commented Sep 25, 2020 at 21:26
  • I've done further testing and it seems that date is the only one acting that way. Commented Sep 25, 2020 at 22:41
  • @fluffeh, ah, hmm, I'll try to re-elaborate. If I run PS1="$(date)" now, the date is called immediately, and PS1 is set to Sat Sep 26 10:36:34 EEST 2020 . That's the string that then prints as prompt every time. However, if I run PS1="\$(date)", date isn't run yet, but PS1 gets set to $(date) . This causes it to run date every time the prompt is printed, and the result to be printed as the prompt. In neither case does the assignment to PS1 itself print anything.
    – ilkkachu
    Commented Sep 26, 2020 at 7:40

You must log in to answer this question.

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