Bash – way to execute code in the command line prompt (PS1) without using backticks

bashcommand-substitutionpromptquotingshell

I am using this piece of code directly in the command prompt (PS1), and it tells me whether the previous command executed correctly.

PS1="\`if [ \$? = 0 ]; then echo -e \"\e[1;32m[⚡️ ]\"\e[0m; else echo -e \"\e[1;31m[? ]\"\e[0m; fi\`-[\u@\h: \w]"

I don't like the backticks notation. Is there a way to execute it without using “?

Also, is there a reason this would interfere with the results from a another script? I've exposed a function that I called in the command prompt, but this piece messes up the results. The function gets called only once when PS1 is exported and not every time that the command prompt is loaded.

Update 1:
So I tried the plain "$()" but it didn't work. And, now I am more puzzled because if add a backslash to it works – "\$()". Why is this? Does anyone know of this? Does "$" need to be escaped?

The original works:

export PS1="[\`if [ \$? = 0 ]; then echo -e \"\e[1;32m[⚡️ ]\"\e[0m; else echo -e \"\e[1;31m[? ]\"\e[0m; fi\`]-[\u@\h: \w] \$ "

Result:

[⚡️ ]-[rordev@Luiss-MBP: ~/Development/test] $

This doesn't work:

export PS1="[$(if [ $? = 0 ]; then echo -e \e[1;32m[⚡️ ]\e[0m; else echo -e \e[1;31m[? ]\e[0m; fi)]-[\u@\h: \w] \$ "

Result:

-bash: 32m[⚡️: command not found
[e[1]-[rordev@Luiss-MBP: ~/Development/test] $

But this works. Why? and why is the backslash needed before$()?

export PS1="\$(if [ \$? = 0 ]; then echo -e \"\e[1;32m[⚡️ ]\"\e[0m; else echo -e \"\e[1;31m[? ]\"\e[0m; fi)-[\u@\h: \w] \$ "

Result:

[⚡️ ]-[rordev@Luiss-MBP: ~/Development/test] $ 

Update 2:
I tried the suggestions and it works. Well, sort of.

I have to call the conditional first and the function last.

PS1="\$(if [ \$? = 0]; then ...; else ...; fi)-[\u@\h: \w\$(myFunction)]"

But it doesn't work the other way.

PS1="[\u@\h: \w\$(myFunction)]-\$(if [ \$? = 0]; then ...; else ...; fi)"

The function is called and the results are displayed, but the conditional does not seem to be executing, or rather the status code returned seems to always be 0. So it always shows the first part of the conditional.

Any ideas about that? I suspect that it has something to do with the order in which the command substitutions are executed.

Best Answer

PS1="\`if [ \$? = 0 ]; then ... fi\`

Update: So I tried the plain "$()" but it didn't work. And, now I am more puzzled because if add a forward slash to it works - "\$()".

The \ is a backslash, not a forward slash.

You need to escape the $ here for the same reason you escaped the backticks in the first snippet: because otherwise the command substitution is expanded immediately, when setting PS1, and not when PS1 is used to produce a prompt.

You're better off using single quotes around the assignment, they'll prevent expanding variables and command substitutions for the whole string.

PS1='$(if [ $? != 0 ]; then echo -e "\[\e[1;31m\][boom]\[\e[0m\] "; fi)\u@\h \w\$ '

Note, that you need to wrap the escape codes within \[ ... \] to tell bash that they don't print, and that it shouldn't take them into account when calculating the width of the prompt (mentioned in passing in the manual). (I don't know if Bash can correctly deal with the graphic characters you used, and I can't test.)

Related Question