1. 34
  1.  

  2. 10

    There is a prompt that I saw here on lobste.rs a couple of months ago but have been unable to find again: A Bash prompt which added a timestamp to the row when the user presses enter and the command is executed, as opposed to when the prompt appears and starts accepting user input. Does anyone happen to have a link to that blog post lying around?

      1. 1

        What kind of latency does that add?

        Having (\t) in PS1 was a game changer for me. Most of the time I’m quick enough that it doesn’t matter, but every once in a while the time delay causes a headache.

        1. 1

          the latency is probably unnoticeable. Do you notice e.g. the rsync progress bar updating? It’s the same process.

          1. 1

            Should be trivial.

            Presumedly, the shell is doing a function call to a shared library to get the time which should be fast.

            Much faster than invoking date on every instance I would think.

          2. 1

            That’s really cool. Wonder if this method lets you update the prompt at any time?

            1. 1

              yep.

          3. 4

            One thing I’ve been doing for years is put the timestamp on the right side of the screen; I don’t know how to do this in bash off-hand, but in zsh you can set it with RPROMPT='%T'.

            I actually have a slightly more advanced version which also shows the hostname, but only on ssh connections:

            set_rprompt() {
                host=
                [[ -n "${SSH_CLIENT:-}${SSH2_CLIENT:-}${SSH_CONNECTION:-}" ]] && host="%F{red}%U%B%m%b%u%f:"
                print "${host}%T"
            }
            RPROMPT=$'$(set_rprompt)'
            

            Putting it on the right moves it “out of the way” of the more important directory and git branch, but it’s still there when I want it.

            1. 1

              You could do it with some terminal movement commands.

              For me though, because I frequently toss together multiple commands in the shell before making a script, the date would either get overwritten, or the logic to prevent that would be absurd.

          4. 7

            I wonder why people seem to generally dislike two line prompts? I’ve fell in love with idea as soon as I’ve realized it is possible:

            14:39:29|~/projects/rust-analyzer|master⚡*
            λ 
            

            Having command at a fixed offset form the terminal edge makes scanning history of commands much easier, full path gives essential context, and time & git status are just nice touches.

            Am I missing some reasons why single line prompts are more convenient?

            1. 5

              Those are my reasons: predictability/ease of scanning. Most of my prompt is built to be as visually quiet as possible to help me focus. It’s a micro-optimization, but I love the feeling of it.

              The only real issue with two line prompts that I know of is that fish has a few open bugs around handling of redraws in the presence of those. But that’s about it.

              1. 5

                For me it’s mostly about reducing visual noise, everything I want in a prompt (directory and git status) fits comfortably in one line, optionally showing the exit status if it’s different from 0.

                1. 2

                  I just stick all that crap into RPROMPT, why waste two lines with optional information when the right prompt can deal with it and get overwritten if what you type gets longer?

                  1. 1

                    I‘ve tried the right prompt, but two lines work better for me, amusingly, for exactly same reason :)

                    Vertical space is cheap win infinite scroll, horizontal spaces feels significantly more crowded.

                    1. 2

                      We’ll have to disagree I guess then. My prompt in $HOME is literally:

                      $ .......a long way over to the right ->~
                      

                      The right fills up with git status and dir information as I chdir around but otherwise I can’t stand my prompt taking up a bajillion characters based on the directory I’m in. I want all the crap i type to be at index 2 always. But thats just my weirdness really.

                      Also means less lines to delete when copy/pasting my history.

                  2. 2

                    My prompt is 2 lines, but the second line has nothing. It’s really nice to start commands at column 0, and nudges me to use multi-line commands more.

                    1. 1

                      Mine is two lines as well, which kind of freaks out some people who don’t know it can even do that. This is mine, but I’d like to check out the return value stuff:

                      # define the unprinting start and end escape sequences, so bash doesn't
                      # count these as taking up room on the command line
                      UPb="\["
                      UPe="\]"
                      
                      # Setup color variables
                      BLACK="$UPb\033[0;30m$UPe"
                      DGRAY="$UPb\033[1;30m$UPe"
                      RED="$UPb\033[0;31m$UPe"
                      LRED="$UPb\033[1;31m$UPe"
                      GREEN="$UPb\033[0;32m$UPe"
                      LGREEN="$UPb\033[1;32m$UPe"
                      BROWN="$UPb\033[0;33m$UPe"
                      YELLOW="$UPb\033[1;33m$UPe"
                      BLUE="$UPb\033[0;34m$UPe"
                      LBLUE="$UPb\033[1;34m$UPe"
                      PURPLE="$UPb\033[0;35m$UPe"
                      LPURPLE="$UPb\033[1;35m$UPe"
                      CYAN="$UPb\033[0;36m$UPe"
                      LCYAN="$UPb\033[1;36m$UPe"
                      LGRAY="$UPb\033[0;37m$UPe"
                      WHITE="$UPb\033[1;37m$UPe"
                      NEUTRAL="$UPb\033[0m$UPe"
                       
                      export BLACK DGRAY RED LRED GREEN LGREEN BROWN YELLOW BLUE
                      export LBLUE PURPLE LPURPLE CYAN LCYAN LGRAY WHITE NEUTRAL UPb UPe
                      
                      export PS1="*** $LCYAN\@$NEUTRAL *** $YELLOW\w$NEUTRAL  ***\n"
                      

                      I add the \h for host name in my work shell, because I ssh to a lot of places

                      1. 2

                        You can replace all that color stuff with %F{...} syntax, it’s going to be more readable.

                        1. 1

                          That just shows you how long I have dragged this along! And is that true as well for bash?

                          1. 1

                            Honestly, idk. I discovered %F stuff a week ago, before that my config had a lot of vars with ANSI escapes too! :)

                      2. 1

                        Like you I prefer two line prompts primarily for the ease of scanning. My informational line does not drastically differ between locations and projects, but having a set size/location for my commands makes it very easy for me to scan.

                      3. 5

                        I’m not so good at shell, so instead I wrote a little Zig program that prints my prompt, and just have a helper function in shell that passes it anything it needs.

                        prompt_helper() {
                            if test -d .git || git rev-parse --is-inside-work-tree > /dev/null 2>&1
                            then
                                gs="$(git status --porcelain --branch --ahead-behind)"
                            else # remove old status
                                unset gs
                            fi
                            prompt "$1" "$USER" "$(hostname)" "$HOME" "$PWD" ${gs:+"$gs"}
                        }
                        
                        PS1="\$(prompt_helper \$?)"
                        

                        I don’t know if that’s a good way to detect a git repo. As I said, not good at shell.

                        1. 4

                          I saw someone using just ‘;’ as a prompt on twitter, apparently cribbed from the rc shell. It means you can copy multiple lines from history and re-execute them on paste.

                          It’s significantly more minimal than my own minimal prompt, and inspiring.

                          1. 3

                            BTW this tickled a bug, which I fixed. The next release of Oil will be able to run punctual :)

                            https://github.com/oilshell/oil/issues/853

                            $ bin/osh
                            [osh] lisa ~/git/oilshell/oil$ . /home/andy/git/wild/shell-prompt/punctual/punctual.sh 
                             lisa ▶ true
                             lisa ▶ false
                             lisa ▶ 1 ▶ true
                            
                            1. 1

                              Glad it was of some use, thanks!

                            2. 1

                              Yeh I’m one of those ‘;’ people these days. I really like the lack of noise as others have called out in this thread. I also colour the ‘;’ red on non-zero exit code (don’t really care for knowing the code value straight away). For dir tracking I use zsh to signal the title of my terminal emulator (currently vterm in Emacs but works anywhere else)

                            3. 4

                              Indicating the return status of the last command is really useful, but I’ve found that just colour is too subtle most of the time. If you do this, you may want to experiment with putting the error code in the prompt if it’s not zero. Something like

                              %(?..(%?%))
                              

                              to print (1) if the exit status was 1, for example.

                              1. 1

                                Riiight, I tried doing that and didn’t like it. So far that color-coded prompt seems to be noticeable enough for me, but maybe that’s because of novelty, I’ll see. :)

                                1. 1

                                  Fwiw, I just use:

                                  setopt print_exit_value
                                  

                                  That way my prompt never changes, and I get the actual return code printed out blatantly like so:

                                  zsh: exit 129   ~/sync.sh
                                  

                                  I’d rather know the actual return code, and do nothing if everything is ok and not clutter the prompt at all.

                                  1. 2

                                    That’s exactly what I replaced with colorful >. :-) I’ve been living with print_exit_value for a long time but it’s nice when command output is exactly command output. :)

                                    1. 1

                                      Heh, I’d rather have the extra lines in this case so its obvious that something exited non zero. To each their own!

                                2. 1

                                  for those who care about a visible exit code, I found

                                  setopt PRINT_EXIT_VALUE
                                  

                                  a nice personal solution. It does not go in your prompt

                                  1. 1

                                    I gotta refresh my tabs more often heh jinx but I agree entirely.

                                  2. 1

                                    IMO, I’m not a huge fan of this, as the fact that the exit status is not zero does not always mean an error has occurred. I suppose it really comes down to workflows and what tools you use all the time. But my prompt turning red because my compile failed is not any more informative than the three pages of errors I got prior to that. :)

                                    1. 2

                                      …exit status is not zero does not always mean an error has occurred.

                                      Indeed. I just use it as a useful point of information for those commands whose error codes are siginificant or I can’t tell actually failed. It’s always a personal preference thing, though.

                                  3. 4

                                    I have had pretty good experience so far using Starship. It doesn’t have any significant slowdown, and it offers a wide array of informational and formatting options.

                                    1. 3

                                      +1 to starship - it’s nice having the prompt character change color and shape when the previous command fails:

                                      dotfiles on main
                                      △ false
                                      
                                      dotfiles on main
                                      × true
                                      
                                      dotfiles on main
                                      △
                                      
                                      1. 2

                                        Changing shape is easy enough with the code from the article, no need for separate binaries:

                                        p_pr='%(?.%F{blue}△%f.%F{red}×%f)'
                                        
                                        1. 1

                                          good point! I have been tempted to ditch starship for some native fish shell goodness … someday :)

                                    2. 2

                                      Starship has a bunch of this built in, including conditional username display. I love that the username for starship only shows up conditionally: https://starship.rs/config/#username

                                      It also has command runtime for slow commands, colours for exit codes, AND it runs incredibly fast. It’s one of the best things I’ve added to my CLI.

                                      1. 2

                                        You could argue that those things described are also built-in in zsh. :))

                                        1. 1

                                          Not OP, but one of the things I like about starship is that I can use it from different shells, and it looks the same. So at my work, where I can’t use fish, I can still use starship.

                                      2. 2

                                        Stuff like this is one of the things that annoy me about zsh. You can write all sorts of symbol noise for things like PROMPT, globs and expansions. Personally I think

                                            local last_exit=$?
                                        
                                            case $last_exit in
                                                0) last_exit="${fg[green]}${last_exit}$reset_color" ;;
                                                *) last_exit="${fg[red]}${last_exit}$reset_color" ;;
                                            esac
                                        

                                        is more readable.

                                        EDIT: Despite the comment below, you can use ANY string in PROMPT (or PS1) in ZSH. At worst, you have to worry about escaping special characters associated with the PROMPT DSL, namely ‘%’ and ‘)’ which are escaped with ‘%%’ and ‘%)’ respectively.

                                        This is doable trivially in ZSH:

                                        zshprompt_escape_percent() {
                                            REPLY=${*//\%/\%\%}
                                            REPLY=${REPLY//\)/\%\)}
                                        }
                                        zshprompt_escape_percent $prompt_string
                                        PROMPT=$REPLY
                                        

                                        thus using the above snippet I posted could be used like

                                        precmd() {
                                            local last_exit=$?
                                        
                                            case $last_exit in
                                                0) last_exit="${fg[green]}>$reset_color" ;;
                                                *) last_exit="${fg[red]}>$reset_color" ;;
                                            esac
                                            zshprompt_escape_percent $last_exit
                                            PROMPT=$my_prompt$last_exit
                                        }
                                        
                                        1. 1

                                          It would be helpful to indicate how you would do this since you can’t put this sort of thing in your PROMPT. (And if you can’t, indicate that as well.)

                                          1. 1

                                            you can indeed use it in PROMPT (or PS1). you just need to worry about, and escape, % by doubling them up; there is also ) which is escaped with the sequence %). I generally don’t use PROMPT though since mine is multi-line.

                                            I updated my comment though, thanks.

                                        2. 1

                                          I haven’t started tinkering yet, but csh isn’t able to change the prompt after a non-escaped carriage return, or can it? Isn’t this the only way $prompt could be changed on the fly? (Kinda a csh dork, forgive me.)

                                          1. 1

                                            The biggest improvement I made in my prompt in years is to only display the hostname when I am SSH’ed. After all I know what machine I am on physically, so it is just extra noise.

                                            1. 1

                                              Do you display the username by default?

                                              1. 1

                                                I don’t, but I almost never use a different username so YMMV.

                                            2. 1

                                              I would like to share a prompt hack I made for my shell prompt about a year ago. I show when any capital enviroment variables are changed, such as $PYTHONPATH: link. This allows me to see if I’m in an abnormal operating environment (a situation that occurs when working occasionally, and has the potential to be very annoying)

                                              1. 1

                                                tbh I used to have a big ole prompt and an rprompt. When I switched back fulltime to ksh, I took some time to do the same as OP, but ended up with this prompt: ~|11:26:49|0$. Just the basename of cwd, time and the return code of the last command. I’ve never had occasion to need a more up-to-date time.

                                                I’m oncall a lot and do ops which results in needing to copy/paste into slack, irc, tickets, etc. and honestly an rprompt was too disruptive there and a multiline prompt to me just looks like too much line noise.