-
Notifications
You must be signed in to change notification settings - Fork 4
Prompt
shed draws its prompt from the $PS1 variable. Before each prompt is shown, PS1 is run through a pass of prompt escape sequences - backslash codes that expand into dynamic content like the working directory, the last command's runtime, or the output of a shell function. There is also a right-hand prompt ($PSR) and a full status line, both of which are expanded the same way.
If $PS1 is unset, shed falls back to a built-in default (a multi-line, colored prompt showing user, host, working directory, and the prompt symbol).
| Escape | Expands to |
|---|---|
\u |
the current username ($USER) |
\h |
the hostname, up to the first .
|
\H |
the full hostname |
\w |
the working directory, with $HOME shown as ~
|
\W |
the working directory, truncated to its last few segments (see below) |
\s |
the shell name (shed) |
\$ |
# when running as root (uid 0), otherwise $
|
\t |
the last command's runtime, in milliseconds |
\T |
the last command's runtime, human-readable (e.g. 1m 3s) |
\j |
the number of currently-running jobs |
\n |
a newline |
\r |
a carriage return |
\\ |
a literal backslash |
\" \'
|
a literal quote character |
\c{...} |
a named color/style (see Colors and Styling) |
\e[...] |
a raw ANSI escape sequence |
\@name |
the output of shell function name (see Embedding Output) |
\nnn |
the byte given by up to three octal digits |
Note that \W is not just the basename (as it is in bash). It's the working directory trimmed to its last N path segments, where N is set by shopt prompt.trunc_prompt_path (default 4). So in /usr/local/share/man, \w gives /usr/local/share/man and \W gives local/share/man (with the default of 4). Set prompt.trunc_prompt_path lower for a shorter path, higher to show more.
There are two ways to color a prompt.
The \c{...} escape takes a style description and emits the matching ANSI code. This is the same grammar used by the highlight.* options, so it accepts named colors, their bright variants, the modifiers bold/italic/underline/dim/strikethrough, hex colors (#rrggbb), and backgrounds via on:
export PS1='\c{bold green}\u\c{reset}@\c{#89b4fa}\h\c{reset} \W \$ '\c{reset} clears styling back to the terminal default. Because \c{...} is human-readable and doesn't require memorizing escape codes, it's the recommended form.
If you'd rather write escape codes directly, \e[...] passes a raw ANSI sequence straight through:
export PS1='\e[1;32m\u@\h\e[0m \W \$ 'The \@ escape embeds the output of a shell function directly in the prompt. Define a function that prints something, then reference it by name:
gitbranch() { git branch --show-current 2>/dev/null; }
export PS1='\u@\h \W \@gitbranch \$ 'The function runs on every prompt draw, and its standard output is spliced in where \@ appears. The name runs until the first character that can't be part of an identifier; if you need to butt it up against following text, use the braced form \@{name}:
export PS1='[\@{gitbranch}] \$ '\@ only invokes functions, not arbitrary commands - so wrap whatever logic you need (pipelines, conditionals, external tools) inside a function and reference that.
Two mechanisms let the prompt reflect live state.
Substitution: When shopt prompt.substitute is enabled (the default), the expanded prompt is run through a second pass of variable and command substitution. That means $VAR and $(...) inside PS1 are evaluated fresh each time the prompt is drawn:
export PS1='[$?] \W \$ ' # shows the last exit code
export PS1='$(date +%H:%M) \$ ' # shows the current time(Disable it with shopt prompt.substitute=false if you want a literal $ in your prompt without escaping it.)
On-demand Redraw: Sending SIGUSR1 to the shell forces it to redraw the prompt. Combined with \@ or $(...), this enables asynchronous prompt content: kick off a slow computation (a git status on a huge repo, say) in the background, have it stash its result somewhere and signal the shell when it's done, and the prompt updates without blocking your typing. The IPC socket's msg and redraw requests (see IPC-Socket) are a convenient way to drive this from a background job.
$PSR is a second prompt string, rendered flush against the right edge of the prompt's last line. It's expanded with exactly the same escape sequences as PS1:
export PSR='\c{dim}\T\c{reset}' # runtime of the last command, on the rightPSR must fit on a single line - if it expands to multiple lines, only the first is used (and a warning is logged) - and it's only drawn when there's room for it alongside the main prompt.
The prompt-rendering options are in the prompt.* shopt namespace:
| Option | Effect |
|---|---|
prompt.trunc_prompt_path |
segments shown by \W (default 4) |
prompt.substitute |
run variable/command substitution over the expanded prompt (default true) |
prompt.expand_aliases |
expand aliases visually on the prompt as you type rather than after submitting (default true) |
(The prompt.* namespace also holds a few completion-related options - see Configuration for the full list.)
Prompt escapes aren't limited to PS1. The echo builtin's -p flag runs its argument through the same expander, which makes the escape sequences - especially \c{...} and \T - usable from any script or command:
echo -p '\c{bold green on black}Build succeeded\c{reset} in \T'This is a tidy way to emit colored output without hand-writing ANSI codes.
The status line is an anchored extension of the prompt: a persistent line (enabled with shopt statline.enable=true) that the prompt is drawn against. It's built from three strings, each expanded with the same prompt escapes and substitution as PS1:
shopt statline.enable=true
shopt statline.left_string="\u@\h"
shopt statline.middle_string='$(git branch --show-current)'
shopt statline.right_string='[$?]'Note: the above example requires shopt prompt.substitute=true to expand the right and middle strings.
| Option | Position |
|---|---|
statline.left_string |
flush left |
statline.middle_string |
centered |
statline.right_string |
flush right |
Because the strings go through full prompt expansion, everything from the escape table works in them - \T, \c{...}, \e[...], \@func - as do $VAR and $(...). A few variables are especially useful here:
-
$SHED_EDIT_MODE- the current line-editor mode (insert,normal,emacs, …) -
$EDITOR_LINE/$EDITOR_LINES- the cursor's line and the total line count of the buffer - the usual
$?,$SHLVL, and friends
The shipped defaults use these to show the edit mode, the last command's runtime, the exit code, and the cursor position - a reasonable starting point to crib from. A fuller worked example lives in examples/status_line.sh.