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.

  • 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

16

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%/*/*}/"}] $ '
  • 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 :( –  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 –  May 26 '21 at 01:52
3

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
  • 131
  • 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