Live data from Hacker News

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

nochlin.com

91–100 of 281 posts

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

#92

if [ -x "$(command -v gtimeout)" ]; then Interesting way to check if a command is installed. How is it better than the simpler and more common "if command...; then"?

The form you propose runs `command`, which may have undesired side-effects. I always thought `which` to be standard, but TIL `command` (sh builtin) is[0].

[0]: https://hynek.me/til/which-not-posix/

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

#93

Earlier quoted context omitted.

If you're trying to write a full fledged program in it, it's going to be a pain as there are only strings (and arrays, I think). Bash is for scripting. If you have complex logic to be done, use another programming language like perl, ruby, python, $YOUR_PREFERRED_ONE,...

You’re arguing that the power of PowerShell is pointless because you’ve resorted to alternatives to bash… because it’s not good enough for common scenarios. This is Stockholm Syndrome. You’ve internalised your limitations and have grown to like them.

No. bash as a shell is for interactive use or for automating said interactions. I want the computer to do stuff. The “everything is a file” and text oriented perspective in the unix world is just one model and bash is very suitable for it. Powershell is another model, just like lisp and smalltalk. I’m aware of the limitations of bash, but at the end of the day, it gets the job done and easily at that.

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

#94

Earlier quoted context omitted.

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

> 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? It's for communicating with the operating system, launching commands and viewing their output. And some scripting for repetitive workflows. If I'd want a full programming environment, I'd take a Lisp machine or Smalltalk (a programmable programming environme…

> In your story, they'd be better of writing a proper program.

Sure, on Linux, where your only common options bash or "software".

On Windows, with PowerShell, I can don't have to write a software program. I can write a script that reads like a hypothetical C# Shell would, but oriented towards interactive shells.

(Note that there is a CS-Script, but it's a different thing intended for different use-cases.)

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

#95
The first four parts of my Typesetting Markdown blog describes improving the user-friendliness of bash scripts. In particular, you can use bash to define a reusable script that allows isolating software dependencies, command-line arguments, and parsing.

https://dave.autonoma.ca/blog/2019/05/22/typesetting-markdow...

In effect, create a list of dependencies and arguments:

    #!/usr/bin/env bash
    source $HOME/bin/build-template

    DEPENDENCIES=(
      "gradle,https://gradle.org"
      "warp-packer,https://github.com/Reisz/warp/releases"
      "linux-x64.warp-packer,https://github.com/dgiagio/warp/releases"
      "osslsigncode,https://www.winehq.org"
    )

    ARGUMENTS+=(
      "a,arch,Target operating system architecture (amd64)"
      "o,os,Target operating system (linux, windows, macos)"
      "u,update,Java update version number (${ARG_JAVA_UPDATE})"
      "v,version,Full Java version (${ARG_JAVA_VERSION})"
    )
The build-template can then be reused to enhance other shell scripts. Note how by defining the command-line arguments as data you can provide a general solution to printing usage information:

https://gitlab.com/DaveJarvis/KeenWrite/-/blob/main/scripts/...

Further, the same command-line arguments list can be used to parse the options:

https://gitlab.com/DaveJarvis/KeenWrite/-/blob/main/scripts/...

If you want further generalization, it's possible to have the template parse the command-line arguments automatically for any particular script. Tweak the arguments list slightly by prefixing the name of the variable to assign to the option value provided on the CLI:

    ARGUMENTS+=(
      "ARG_JAVA_ARCH,a,arch,Target operating system architecture (amd64)"
      "ARG_JAVA_OS,o,os,Target operating system (linux, windows, macos)"
      "ARG_JAVA_UPDATE,u,update,Java update version number (${ARG_JAVA_UPDATE})"
      "ARG_JAVA_VERSION,v,version,Full Java version (${ARG_JAVA_VERSION})"
    )
If the command-line options require running different code, it is possible to accommodate that as well, in a reusable solution.

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

#96
post #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 [[

It's just another Lisper wishing they weren't writing Bash right now.

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

#97
post #80

Earlier quoted context omitted.

> "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 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 has up-front required prerequisites that you can declare: https://learn.microsoft.com/en-us/powershell/module/microsof...

Not that that's needed, because Get-NetTcpConnection is a built-in command.

3. Your script is very bravely trying to parse output that includes many different protocols, including: tcp, tcp6, udp, udp6, and unix domain sockets. I'm seeing random junk like 'ACC' turn up after the first awk step.

4. Speaking of which, the task was to get tcp connections, not udp, but I'll let this one slide because it's an easy fix.

5. Now imagine putting your script side-by-side with the PowerShell script, and giving it to people to read.

What are the chances that some random person could figure out what each one does?

Would they be able to modify the functionality successfully?

Note that you had to use 'awk', which is a parser, and then three uses of 'grep' -- a regular expression language, which is also a kind of parsing.

The PowerShell version has no parsing at all. That's why it's just 4 pipeline expressions instead of 9 in your bash example.

Literally in every discussion about PowerShell there's some Linux person who's only ever used bash complaining that PS syntax is "weird" or "hard to read". What are they talking about!? It's half the complexity for the same functionality, reads like English, and doesn't need write-only hieroglyphics for parameters.

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

#98

Here's a script that left an impression on me the first time I saw it: https://github.com/containerd/nerdctl/blob/main/extras/rootl... I have since copied this pattern for many scripts: logging functions, grouping all global vars and constants at the top and creating subcommands using shift.

You may like bash-modules then: https://github.com/vlisivka/bash-modules/tree/master/bash-mo...

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

#99

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 like:

    readonly SCRIPT_SRC="$(dirname "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}")"
    readonly SCRIPT_DIR="$(cd "${SCRIPT_SRC}" >/dev/null 2>&1 && pwd)"
    readonly SCRIPT_NAME=$(basename "$0")

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

#100
post #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 [[

Depends on the CI used, I guess. Gitlab CI and Github Actions show colors and I use them deliberately in a format check job to show a colored diff in the output.
Post reply on HN