11

How can I create a bash and a zsh prompt that shows only the current directory and its parent directory?

For example, if I'm at the dir ~/pictures/photos/2021, it should show:

[photos/2021]$ echo hi

That's all. Would like it for bash and for zsh.

blackyellow
  • 609
  • 2
  • 4
  • 15
  • 1
    Relating https://unix.stackexchange.com/q/381113/117549; PROMPT_DIRTRIM works very similarly (it elides the initial paths into `...`). Also https://unix.stackexchange.com/questions/273529/shorten-path-in-zsh-prompt – Jeff Schaller May 24 '21 at 14:03

2 Answers2

17

In zsh:

PS1='[%2d] $ '

See info zsh 'prompt expansion' for details.

In bash (or zsh -o promptsubst, though you wouldn't want to do that there as if $PWD contains % characters, that would cause further prompt expansions):

PS1='[${PWD#"${PWD%/*/*}/"}] $ '
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
  • how PWD expand within single quotes? or maybe it does differently for the PS1 or prompts? really I cannot understand how it is expanded! – αғsнιη May 24 '21 at 13:30
  • @αғsнιη, it's not expanded at the time of assignment, but it's expanded each time the prompt is expanded as part of the prompt expansion. – Stéphane Chazelas May 24 '21 at 13:36
  • seems it removes outer quotes then perform variable expansions, etc, is it safe? looks for me it's unsafe if one don't know what they do with it. I didn't know this until today! like for a directory named `; reboot;` – αғsнιη May 24 '21 at 13:37
  • 3
    @αғsнιη, it's as safe as your `$PS1` is. If you set `PS1='$(reboot)'`, then it will reboot of course. That's why you don't want to set `$PS1` to arbitrary values without sanitizing them as part of your `PROMPT_COMMAND` in `bash`. In `zsh`, if you enable the `promptsubst` option, it's a bit worse in that `%x` expansions are done *after* those expansions. It's safer to use the `$psvar` array and `precmd()` there than enabling `prompsubst`. – Stéphane Chazelas May 24 '21 at 13:43
  • what about on having a directory name like `;reboot;` or maybe `;$(reboot);`? that one I don't know what will happen if I use something like `$PWD` in my PS1 or other prompts. Oh, God, that's not safe at all to use thing like this in prompts – αғsнιη May 24 '21 at 13:46
  • 2
    @αғsнιη, `PS1='$PWD'` is safe in that case in that expansion is not going to be done recursively. `$PWD` will be expanded to its value, but if that value has some `$`s or backticks, that will not be further expanded. The prompt would be if you your `$PROMPT_COMMAND` does something like `PS1="$PWD ... "` (note the double quotes) – Stéphane Chazelas May 24 '21 at 13:52
  • the bash prompt is not working :( – blackyellow May 24 '21 at 15:04
  • @blackyellow, in which way is it not working for you? It's working for me within `bash --norc` and bash 5.1 (and also even an ancient bash 3.2) on Debian GNU/Linux. – Stéphane Chazelas May 24 '21 at 15:11
  • Works for me. Could maybe use something like `PROMPT_COMMAND='PWD2="${PWD/#$HOME/\~}"'` and `PS1='[${PWD2#"${PWD2%/*/*}/"}] $ '` to show the home directory as `~`. – ilkkachu May 24 '21 at 15:37
  • I think it did not work because I tried to set an `alias ps3='PS1=\'[${PWD#"${PWD%/*/*}/"}] $ \''` because sometimes i like to switch prompts. However, it did work by pasting it directy on the command line. I actually solved it by using double quotes and proper scape caracters – blackyellow May 26 '21 at 01:52
4

Another option that may be more readable:

PS1='[$(basename $(dirname "$PWD"))/$(basename "$PWD")]'

This also shows how you do similar directory operations more generally.

gntskn
  • 141
  • 2
  • 3
    Note that that solution is for `bash` or other shells that perform other expansions upon prompt expansions. There's a minor glitch in that it gives `///` when you're in `/` or `//etc` when in `/etc` for instance. It does strip trailing newline characters in those path components. It means starting at least 3 processes and executing three external processes in them at each prompt. So in the end, I wouldn't go for that approach. – Stéphane Chazelas May 25 '21 at 05:39