Live data from Hacker News

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

nochlin.com

101–110 of 281 posts

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

#102
post #60
post #18

Don't output ANSI colour codes directly - your output could redirect to a file, or perhaps the user simply prefers no colour. Use tput instead, and add a little snippet like this to the top of your script: command -v tput &>/dev/null && [ -t 1 ] && [ -z "${NO_COLOR:-}" ] || tput() { true; } This checks that the tput command exists (using the bash 'command' builtin rather than which(1) - surprisingly, which can't alwa…

There should just be a command for this. Like echo with a color flag that does something if you’re in a tty.

But since there isn’t, even if you make one, people won’t want to rely on it as a dependency.

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

#103
post #80

Earlier quoted context omitted.

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 po…

I know this sounds like nit-picking but bear with me. It's the point I'm trying to make: 1. Your script outputs an error when run, because 'bash' itself doesn't have netstat as a built-in. That's an external command. In my WSL2, I had to install it. You can't declaratively require this up-front, you script has to have an explicit check... or it'll just fail half-way through. Or do nothing. Or who knows!? PowerShell h…

Sure, I'm not arguing that having a set of well defined outputs and passing objects around wouldn't be better. You're talking to someone that often laments that SmallTalk was not more popular. But you'd need to get the entire OSS community to land on a single object representation and then get them to independently change all the tools to start outputting the object version. PowerShell and Microsoft have the advantage in this case of being able to dictate that outcome. In the linux world, dictating outcomes tends to get you systemd levels of controversy and anger.

Technically speaking though, there's no reason you couldn't do that all in bash. It's not the shell that's the problem here (at least, to an extent, passing via text I guess is partly a shell problem). There's no reason you couldn't have an application objNetStat that exported JSON objects and another app that filtered those objects, and another that could group them and another that could sort them. Realistically "Sort-Object Count -Descending -Top 10" could be a fancy alias for "sort | uniq -c | sort -r | head -n 10". And if we're not counting flags and arguments to a function as complexity, if we had our hypothetical objNetstat, I can do the whole thing in one step:

  objNetstat --json \
  | jq -c '[.[] | select(.state == "ESTABLISHED")] | group_by(.port) | map({port:.[0].port, count: map(.host) | length}) | sort_by(.count) | reverse | [limit(10;.[])]'
One step, single parsing to read in the json. Obviously I'm being a little ridiculous here, and I'm not entirely sure jq's DSL is better than a long shell pipe. But the point is that linux and linux shells could do this if anyone cared enough to write it, and some shells like fish have taken some baby steps towards making shells take advantage of modern compute. Why RedHat or one of the many BSDs hasn't is anyone's guess. My two big bets on it are the aversion to "monolithic" tools (see also systemd), and ironically not breaking old scripts / current systems. The fish shell is great, and I've built a couple shell scripts in it for my own use, and I can't share them with my co-workers who are on Bash/ZSH because fish scripts aren't Bash compatible. Likewise I have to translate anyone's bash scripts into fish if I want to take advantage of any fish features. So even though fish might be better, I'm not going to convince all my co-workers to jump over at once, and without critical mass, we'll be stuck with bash pipelines and python scripts for anything complex.

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

#104

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?

You took the words right out of my mouth.

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

#105

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.

Or just the old Perl. Any Bash/AWK/Sed user can be competent with it in days.

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

#107

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

That’s a testament to your distribution/package manager’s stability, not to the language itself. I happen to write my scripts in Elixir (which is as fast-moving as Python 3), using a pinned version of it in a Nix flake at the root of my `~/bin` directory. Scripts from 5 years ago are still as reproducible as today’s.

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

#108
post #25

if [ "$(uname -s)" == "Linux” ]; then stuff-goes-here else # Assume MacOS While probably true for most folks, that’s hardly what I’d call great for everybody not on Linux or a Mac.

Eh. It’s true for most, and if not, it’s probably still a *BSD, so there’s a good chance that anything written for a Mac will still work. That said, I’ve never used any of the BSDs, so I may be way off here.

even a certified unix

https://www.opengroup.org/openbrand/register/brand3700.htm

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

#109

Earlier quoted context omitted.

> shell scripts are the wrong solution for anything over ~50 lines of code. I don't think LOC is the correct criterion. I do solve many problems with bash and I enjoy the simplicity of shell coding. I even have long bash scripts. But I do agree that shell scripting is the right solution only if = you can solve the problem quickly = you don't need data structures = you don't need math = you don't need concurrency

In my opinion, shell scripting is the right tool when you need to do a lot of calling programs, piping, and redirecting. Such programs end up being cumbersome in "proper" languages.

"you can do anything not matter how horrible you feel"

but yea, shell is foremost a composition language/environment

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

#110

Earlier quoted context omitted.

I know this sounds like nit-picking but bear with me. It's the point I'm trying to make: 1. Your script outputs an error when run, because 'bash' itself doesn't have netstat as a built-in. That's an external command. In my WSL2, I had to install it. You can't declaratively require this up-front, you script has to have an explicit check... or it'll just fail half-way through. Or do nothing. Or who knows!? PowerShell h…

Sure, I'm not arguing that having a set of well defined outputs and passing objects around wouldn't be better. You're talking to someone that often laments that SmallTalk was not more popular. But you'd need to get the entire OSS community to land on a single object representation and then get them to independently change all the tools to start outputting the object version. PowerShell and Microsoft have the advantag…

Half way through your second paragraph I just knew you'd be reaching for 'jq'!

All joking aside, that's not a bad solution to the underlying problem. Fundamentally, unstructured data in shell pipelines is much of the issue, and JSON can be used to provide that structure. I'm seeing more and more tools emit or accept JSON. If one can pinch their nose and ignore the performance overhead of repeatedly generating and parsing JSON, it's a workable solution.

Years ago, a project idea I was really interested for a while was to try to write a shell in Rust that works more like PowerShell.

Where I got stuck was the fundamentals: PowerShell heavily leans on the managed virtual machine and the shared memory space and typed objects that enables.

Languages like C, C++, and Rust don't really have direct equivalents of this and would have to emulate it, quite literally. At that point you have none of the benefits of Rust and all of the downsides. May as well just use pwsh and be done with it!

Since then I've noticed JSON filling this role of "object exchange" between distinct processes that may not even be written in the same programming language.

I feel like this is going to be a bit like UTF-8 in Linux. Back in the early 2000s, Windows had proper Unicode support with UTF-16, and Linux had only codepages on top of ASCII. Instead of catching up by changing over to UTF-16, Linux adopted UTF-8 which in some ways gave it better Unicode support than Windows. I suspect JSON in the shell will be the same. Eventually there will be a Linux shell where everything is always JSON and it will work just like PowerShell, except it'll support multiple processes in multiple languages and hence leapfrog Windows.

Post reply on HN