The little set of $PS* variables that are hiding on standard linux machines are one of those hidden nuggets of awesome that, once you discover, lead to numerous kinds of fun! Give it a try on your machine, and see how each are set:

PS1

This is the primary prompt string. The default on my machine is quite spectacular:


echo $PS1
\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$

and this results in the expected path to my present working directory, for example:


~/Documents/Dropbox/Website/vsoch.github.io/vsoch.github.io.new$

Now we can try changing it, and seeing what happens! All you have to do is set PS1 in a terminal, and press enter.


PS1="pancakes> "
pancakes> 

This is one of those “my world is rocked” moments. I’ve always wanted pancakes in my prompt! If you export the variable in your .bash_profile or .profile or similar, you can have pancakes all the time.

PS2

This is the prompt that you see when you press enter during a command (newline) but you forget a quote or something like that. The default is a little carrot, and it’s easiest to just show you. First, here is the default:


$ echo $PS2
>

car="I once was riding in a red velvet car and>
>
>

and it goes away when I complete the statement with the second quote. Now, let’s try changing it to something else.


PS2='keepgoing>'
$ car="this is a car
keepgoing>
keepgoing>
keepgoing>

and there you have it! You could use a motivational message, or something more appropriate…


car="I once was..
taco!
taco!
taco!

PS3

This is what gets shown when there is a select command. Take a look at this example:


#!/bin/bash
# favorite-color.sh
# chmod u+x favorite-color.sh
select color in blue green orange red exit
do
  case $color in
    blue) echo "Blue!";;
    green) echo "Green!";;
    orange) echo "Orange!";;
    red) echo "Red!";;
    exit) exit;;
  esac
done

Let’s look at the default $PS3, it’s not set.


$ echo $PS3

When we run it without that set, we get this.


./favorite-color.sh 
1) blue
2) green
3) orange
4) red
5) exit
#? 1
Blue!
#? 5

I entered 1 and it selected blue, and I entered 5 and exit. Now let’s try setting it:


PS3="What is your favorite color? " ./favorite-color.sh 
1) blue
2) green
3) orange
4) red
5) exit
What is your favorite color? 3
Orange!
What is your favorite color? 5

That’s super cool! It’s such an easy way of giving a prompt.

PS4

And here is the most mysterious (at least to me). This is what gets printed before a trace, and so if you set the calling /bin/bash to have -x it’s going to do this. You can look at the bash man pages for some interesting snippets about how this works, and I have a feeling hidden in these pages is going to be the answer to this riddle, if not a good starting point for solving it. First, here is the default on my machine:


$ echo $PS4
+

and so if I use a small example script and run it:


#!/bin/sh -x

printenv | grep HOME
echo hello world!

I get the expected output, with a little + before the trace of each line.


./hello-world.sh 
+printenv
+grep HOME
HOME=/home/vanessa
+echo hello world!
hello world!

Riddle Me This…

And herein lies the challenge for us to think about today! This example comes from a recent pull request discussion, I noticed this (bug?) that appeared to be inconsistent output between (the same!) calls:


./hello-world.sh 
++printenv
grep HOME
HOME=/home/vanessa
+echo hello world!
hello world!

We isolated it to Ubuntu and the case of using -x, but didn’t go beyond that. Later as I was developing something else that warranted changing the prompt, I realized that this mysterious PS4 existed, period, and that the repeated + character in the bug was in fact, exactly that. How do we know? If we change it to something else, it changes appropriately.


PS4='pancakes' ./hello-world.sh 
pancakesprintenv
pancakesgrep HOME
HOME=/home/vanessa
pancakesecho hello world!
hello world!

(and yes, this lovely discovery turned into this huge sidetrack of a post to talk about it, I’m ok with this. And so herein lies the puzzle, please help to solve it, because I haven’t yet!

Why do we sometimes see a double print of $PS4?

I think likely it has to do with the fact that we are doing this trace and print relative to a pipe. But I don’t know the answer. I’m hoping the rest of the internet (you!) can help!

Want to learn more?

For a nice review and different fun options, see this post, and this one, or for how to also play with colors, this one. If you come up with some awesome settings, please share!