Live data from Hacker News

Help Message for Shell Scripts

samizdat.dev

111–120 of 129 posts

Re: Help Message for Shell Scripts

#111
> $0 means a filename of a file that is being executed.

This is only a convention and is entirely up to the calling program.

For example in bash scripts you can use `exec -a name ...` to pass "name" as the 0th argument.

If you are already using #!/bin/bash you might as well use ${BASH_SOURCE[0]} to get the path to the current script.

Re: Help Message for Shell Scripts

#112
post #8

Earlier quoted context omitted.

You can also use add a hyphen ( https://linuxhint.com/bash-heredoc-tutorial/

I've always avoided that for fear that my or someone else's editor will accidentally replace the tabs with space. Mixed is not a common configuration, these days.

This makes me want to use this just to get people to fix their broken editors.

Re: Help Message for Shell Scripts

#113
post #40

Earlier quoted context omitted.

I also really like the "flag" package for Go, it generates the help text for you and easily lets you set defaults as well as helps you type-check inputs.

I like https://github.com/jpillora/opts for Go arg parsing. It has better, sane defaults with long/short opts.

Cool, I'll check it out. There's something attractive about using stuff from the standard library though.

Re: Help Message for Shell Scripts

#114

The power is out on your boat, again. It’s 3am. You suspect that, again, the alternator housing has come loose. You duct tape a flashlight to the bulkhead so you can work hands free and actually see what you are doing. All you have on you is a broken pocket knife but it’ll do because all you need to accomplish right now is to tighten the housing screws enough . You know this for a fact because you’ve done it three ti…

+1 for the sailing analogy!

"Necessity is the mother of invention" must have been coined by a sailor.

Re: Help Message for Shell Scripts

#115
post #59

Earlier quoted context omitted.

Or just a multiline string: #!/bin/bash USAGE="my-script — does one thing well Usage: my-script Options: Input file to read. Output file to write. Use '-' for stdout. -h Show this message. " help() { echo "$USAGE" } This is my standard approach which is cleaner for putting the documentation at the very top of the file like the linked article.

Thank you! I had no idea that multiline strings were valid bash.

It's the same logic that allows you to type:

git commit -m "First line of commit

Second line of commit"

That's a multi-line string in bash.

Re: Help Message for Shell Scripts

#116
post #93

Earlier quoted context omitted.

Thank you for this really helpful comment. It's like an encyclopedia's worth of bash information in one go--much appreciated.

You're welcome! Shell scripting has a weird language, unsafe by default, and very prone to mistakes... but knowing it well pays off. People say that for complex things it's better to write Python, but that doesn't fly in embedded or Docker environments. Python is not even present in the default Ubuntu Docker images. Also if all you want to do is really write glue code between CLI programs, shell scripting is the way…

I'll second the thanks. Thanks!

Re: Help Message for Shell Scripts

#117
post #64

I learnt the same trick some years ago, from an article called Shell Scripts Matter : https://dev.to/thiht/shell-scripts-matter So I took some of the advice and tips offered in there, and wrote a template file to be used as a baseline when writing scripts for any project that might need one: https://github.com/j1elo/shell-snippets/blob/master/template... Other resources that I link in the readme of that repo, because…

A bash pitfall which I have experienced but didn’t see mentioned is the behavior of the `set -e` (errexit) option when using command substitution. If you expect failures within the command substitution to cause the script to exit, you’re gonna be confused. https://twitter.com/hellsmaddy/status/1273744824835796993?s=... Tl;dr use `shopt -s inherit_errexit`

Thanks. I wasn't aware of that option. I've added the following to my Bash-specific shell scripts:

    # Cause command substitution to inherit the value of the `errexit` option.
    # Introduced in Bash 4.4
    if [ "${BASH_VERSINFO[0]}" -gt 4 ] ||
      { [ "${BASH_VERSINFO[0]}" -eq 4 ] && [ "${BASH_VERSINFO[1]}" -ge 4 ]; }; then
        shopt -s inherit_errexit
    fi

Re: Help Message for Shell Scripts

#119
post #59

Earlier quoted context omitted.

Or just a multiline string: #!/bin/bash USAGE="my-script — does one thing well Usage: my-script Options: Input file to read. Output file to write. Use '-' for stdout. -h Show this message. " help() { echo "$USAGE" } This is my standard approach which is cleaner for putting the documentation at the very top of the file like the linked article.

Woah, I had no idea multiline strings were even a thing in Bash, I've been using heredocs for help messages since forever! Do you know if these are portable?

As far as I know. The POSIX spec[1] simply declares that in single quotes all characters will be preserved exactly, except for single quotes, which aren't allowed. Likewise, for double quotes, except that it also performs expansions ($) and allows escaping (\).

[1]https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V...

Re: Help Message for Shell Scripts

#120
post #48

Earlier quoted context omitted.

To expand on that pattern: while (( $# )); do case "$1" in -h|--help) usage exit ;; -v|--version) do_version exit ;; -d|--debug) debug=true ;; -a|--arg) arg_value="$2" shift ;; *) if [[ ! -v pos1 ]]; then pos1="$1" elif [[ ! -v pos2 ]]; then pos2="$1" else >&2 printf "%s: unrecognized argument\n" "$1" >&2 usage exit 1 fi esac shift done

The one downside of this is that it doesn't handle squeezing flags as in foo -da bar whereas getopts does. On the other hand, with (the Bash built-in) getopts you're limited to single character flags.

You can do that it will just make things a little less pretty.

    while (( $# )); do
        case "$1" in
            -*h*|--help)
                do_help
                exit
                ;;
            -*v*|--version)
                do_version
                exit
                ;;
            -*d*|--debug)
                debug=true
                ;;&
            -*a*|--arg)
                value="$2"
                shift
                ;;&
        esac
        shift
    done
It doesn't support args of the form -avalue but those a pretty uncommon anyway.
Post reply on HN