Live data from Hacker News

Techniques I use to create a great user experience for shell scripts

nochlin.com

71–80 of 281 posts

Re: Techniques I use to create a great user experience for shell scripts

#71
post #64
post #41

These are all about passive experiences (which are great don't get me wrong!), but I think you can do better. It's the same phenomenon DHH talked about in the Rails doctrine when he said to "Optimize for programmer happiness". The python excerpt is my favorite example: ``` $ irb irb(main):001:0> exit $ irb irb(main):001:0> quit $ python >>> exit Use exit() or Ctrl-D (i.e. EOF) to exit ``` Ruby accepts both exit and q…

On the one hand, being generous in your inputs is always appreciated. On the other hand, the fact that both exit and quit will terminate ruby means the answer to "how do I quit ruby" now has two answers (technically 4 because `quit()` and `exit()` also work, and if we're talking about "least surprise" if you accept "exit" and "quit", why not also "bye" or "leave" or "close" or "end" or "terminate". Python might be su…

> why not also "bye" or "leave" or "close" or "end" or "terminate".

We can include these as well, but each keyword that you include brings diminishing returns at the cost of clutter and inconsistence in the API. Python problematically decides that returns diminish after the first --- “first” according to developers, that is --- possibility in all cases. Ruby anticipates that everyone's first choice will be different and practically maximizes comfort of users.

Re: Techniques I use to create a great user experience for shell scripts

#72

I'd add, in each my Bash scripts I add this line to get the script's current directory: SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) This is based on this SA's answer: https://stackoverflow.com/questions/59895/how-do-i-get-the-d... I never got why Bash doesn't have a reliable "this file's path" feature and why people always take the current working directory for granted!

I've been using

script_dir="$(dirname "$(realpath "$0")")"

Hasn't failed me so far and it's easy enough to remember

Re: Techniques I use to create a great user experience for shell scripts

#73
post #41

These are all about passive experiences (which are great don't get me wrong!), but I think you can do better. It's the same phenomenon DHH talked about in the Rails doctrine when he said to "Optimize for programmer happiness". The python excerpt is my favorite example: ``` $ irb irb(main):001:0> exit $ irb irb(main):001:0> quit $ python >>> exit Use exit() or Ctrl-D (i.e. EOF) to exit ``` Ruby accepts both exit and q…

Bad timing, this is changed in Python 3.12.

Still I’ve always used Ctrl+D, which works everywhere unixy.

Re: Techniques I use to create a great user experience for shell scripts

#74
post #41

These are all about passive experiences (which are great don't get me wrong!), but I think you can do better. It's the same phenomenon DHH talked about in the Rails doctrine when he said to "Optimize for programmer happiness". The python excerpt is my favorite example: ``` $ irb irb(main):001:0> exit $ irb irb(main):001:0> quit $ python >>> exit Use exit() or Ctrl-D (i.e. EOF) to exit ``` Ruby accepts both exit and q…

`exit` will work as expected in Python 3.13: https://docs.python.org/3.13/whatsnew/3.13.html#whatsnew313-...

Re: Techniques I use to create a great user experience for shell scripts

#75

Nowhere in this list did I see “use shellcheck.” On the scale of care, “the script can blow up in surprising ways” severely outweighs “error messages are in red.” Also, as someone else pointed out, what if I’m redirecting to a file?

Always fun trying to read errors in a CI build and they are full of [[

Re: Techniques I use to create a great user experience for shell scripts

#76

Every time I see a “good” bash script it reminds me of how incredibly primitive every shell is other than PowerShell. Validating parameters - a built in declarative feature! E.g.: ValidateNotNullOrEmpty. Showing progress — also built in, and doesn’t pollute the output stream so you can process returned text AND see progress at the same time. (Write-Progress) Error handling — Try { } Catch { } Finally { } works just l…

Bash is crap and powershell an abomination with a few good ideas.

fish, Python, and oilshell (ysh) are ultimately on better footing.

Re: Techniques I use to create a great user experience for shell scripts

#77

Earlier quoted context omitted.

Glow is awesome.

No. Glow connects to internet servers, screw that.

Oops, I actually meant Gum, not Glow. Different project from the same folks.

That said, I use Glow to render markdown sometimes. When and how does it connect to internet servers?

Re: Techniques I use to create a great user experience for shell scripts

#78

Nowhere in this list did I see “use shellcheck.” On the scale of care, “the script can blow up in surprising ways” severely outweighs “error messages are in red.” Also, as someone else pointed out, what if I’m redirecting to a file?

I find shellcheck to be a bit of a nuisance. For simple one-shot scripts, like cron jobs or wrappers, it's fine. But for more complicated scripts or command line tools, it can have a pretty poor signal-to-noise ratio. Not universally, but often enough that I don't really reach for it anymore. In truth when I find myself writing a large "program" in Bash such that shellcheck is cumbersome it's a good indication that i…

I’ve definitely hit places where shellcheck is just plain wrong, but I’ve started to just think of it as a different language that’s a subset of shell. It’s less of a linter and more like using gradual type checking, where there’s no guarantee that all valid programs will be accepted; only that the programs which are accepted are free of certain categories of bugs.

Re: Techniques I use to create a great user experience for shell scripts

#79

Not trying to offend anyone here but I think shell scripts are the wrong solution for anything over ~50 lines of code. Use a better programming language. Go, Typescript, Rust, Python, and even Perl come to mind.

Try running a 6 month old Python project that you haven't run in that time and report back. Meanwhile, 10 year old Bash scripts I've written still run unmodified. Winner by a mile (from a software-longevity and low-maintenance perspective at least): Bash

Isn't compare a Python project to a Bash script an unfair comparison?

Compare a Python script to a Bash script. If your Python3 script (assuming no dependencies) doesn't work after 6 months I got some questions for you.

(And I don't really get how a 6 month old Python _project_ is likely to fail. I guess I'm just good at managing my dependencies?)

Re: Techniques I use to create a great user experience for shell scripts

#80

Earlier quoted context omitted.

What? How are typed objects files? What I’m saying is that in *nix tooling, things are typically designed to do one thing well. So no, I don’t want my shell to also have to talk MySQL, Postgres, SQL Server, DB2, HTTP, FTP, SMTP…

> "So no, I don’t want my shell to also have to talk..." What's the point of the shell, if not to manage your databases, your REST APIs, files, and mail? Is it something you use for playing games on, or just for fun? > designed to do one thing well. Eeexcept that this is not actually true in practice, because the abstraction was set at a level that's too low . Shoving everything into a character (or byte) stream turn…

For fun, I took a crack at your example and came up with this craziness (with the caveat it's late and I didn't spend much time on it), which is made a bit more awkward because grep doesn't do capturing groups:

  netstat -aln \
  | grep ESTABLISHED \
  | awk '{print $4}' \
  | grep -Po '\:\d+$' \
  | grep -Po '\d+' \
  | sort \
  | uniq -c \
  | sort -r \
  | head -n 10
Changing the awk field to 5 instead of 4 should get you remote ports instead of local. But yeah, that will be fragile if netstat's output ever changes. That said, even if you're piping objects around, if the output of the thing putting out objects changes, your tool is always at risk of breaking. Yes objects breaking because field order changed is less likely, but what happens if `Get-NetTCPConnection` stops including a `State` field? I guess `Where-Object` might validate it found such a field, but I could also see it reasonably silently ignoring input that doesn't have the field. Depends on whether it defaults to strict or lenient parsing behaviors.
Post reply on HN