2

In ksh on an old Solaris box I used:

export PS1="$PWD $"

to set the prompt to the current directory. It works great until you cd elsewhere, then you see that it's not evaluating PWD each time. I notice that it's fixed by instead setting PS1 like this:

export PS1="\$PWD $"

Just curious what it's called, how it works, other applications etc. (It's one of those things that's quite resistant to Googling.)

5
  • If you do export PS1='$PWD $' (single, not double, quotes), does that work as well? Commented Oct 16, 2014 at 16:30
  • @MarkPlotnick Yes, doing that means I don't need the \.
    – user13757
    Commented Oct 16, 2014 at 16:37
  • @Poldie: What MarkPlotnick was trying to say is to try it without the `. You'll discover that it doesn't work as soon as you cd` to another directory. Now think what $PWD means and consider why the prompt will always show the same directory regardless of where you're at.
    – slebetman
    Commented Oct 17, 2014 at 2:05
  • @slebetman I think he was quite clearly saying to try with single quotes and without the \, otherwise he would have mentioned the other character (which this site doesn't display properly).
    – user13757
    Commented Oct 17, 2014 at 8:03
  • I wanted to verify that Poldie's old shell would not do parameter expansion within single quotes. It behaved as expected. Commented Oct 17, 2014 at 13:51

2 Answers 2

10

A few pieces of documentation will help to explain this.

From the POSIX standards document for the shell:

The following variables shall affect the execution of the shell:
PS1: Each time an interactive shell is ready to read a command, the value of this variable shall be subjected to parameter expansion and written to standard error.
...
Single-Quotes
Enclosing characters in single-quotes shall preserve the literal value of each character within the single-quotes.
...
Double-Quotes
Enclosing characters in double-quotes shall preserve the literal value of all characters within the double-quotes, with the exception of
$: The dollar sign shall retain its special meaning introducing parameter expansion
...
Escape Character (Backslash)
A backslash that is not quoted shall preserve the literal value of the following character.

So the value of PS1 is subject to parameter expansion, and this is what you want, so that $PWD will be evaluated every time you get a prompt. This means there needs to be an actual $PWD string in the value of PS1. But,

PS1="$PWD $ "

will put the value of PWD at the time the assignment statement is run into PS1. PS1 will be something like /home/poldie $ , and it'll never change after that. You don't want that.

PS1="\$PWD $ "

The backslash will quote the $, so that PS1 contains the literal string $PWD $ . You want this.

PS1='$PWD $ '

will do the same thing. Parameters are not expanded when surrounded by single quotes.

(Note: I originally had all these as export statements because the OP chose to write them as export statements. @Kusalananda removed them. I'm not sure why. Exporting PS1 is a valid choice if you want child shells (such as those spawned by the :sh command in vi) to retain your custom prompt.)

3

The \ character escapes the following (special) character. In this case, it escapes the $, which we usually use to dereference a variable. When the shell evaluates a variable assignment, it first expands the right-hand-side of the expression. Without the \ before $PWD, the shell expands $PWD and assigns the result to PS1.

However, with the \, the shell treats $PWD as a literal string, and assigns it as-is to PS1, so that PS1 contains the string $PWD, and not the expanded value of the variable $PWD. When the shell is about to display the prompt, it once again carries out variable expansion, and this time, because $PS1 contains $PWD, without the \, the shell successfully expands it to the current directory.

The same approach can be used to create dynamic variable names in shell scripts (the NetBSD rcNG system uses this quite widely, especially in scripts controlling network interfaces, where the number of network adapter designations in NetBSD and FreeBSD make it impractical to explicitly code for each one).

You must log in to answer this question.