Live data from Hacker News

Help Message for Shell Scripts

samizdat.dev

91–100 of 129 posts

Re: Help Message for Shell Scripts

#91
post #36
post #8

Earlier quoted context omitted.

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

Seriously, bash has too many obscure features.

Ruby and Perl have `here` docs as well.

And Ruby 2.5 has an enhancement which preserves leading whitespace.

Re: Help Message for Shell Scripts

#93
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…

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 to go.

Happy coding!

Re: Help Message for Shell Scripts

#94

You can also use a "here document" help() { cat Options: Input file to read. Output file to write. Use '-' for stdout. -h Show this message. EOH } If the indentation bugs you, you can use a simpler sed trick to remove leading space so that you can indent it as desired: help() { sed -e 's/ //' Options: Input file to read. Output file to write. Use '-' for stdout. -h Show this message. EOH }

[deleted]

Re: Help Message for Shell Scripts

#95
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`

Re: Help Message for Shell Scripts

#96
post #31

Why is “./script.sh -h” better than “less script.sh”?

I just spent three days explaining a bash script I authored to a tech lead who "doesn't know bash that well". If I had written in more help messages I probably could have preserved more of my time.

Re: Help Message for Shell Scripts

#97
This reminds me of a nice sed one-liner I recently happened to craft.

Do you ever collect families of functions in your shell scripts under different sections? Here's a nice way of printing out all the functions under a given section:

    funs(){ sed -n '/^## /h;x;/'"$1"'/{x;s/^\(\w\+\)().*/\1/p;x};x' "$0";}
Where "sections" are delimited by comments of the form "## Section Name" at the beginning of a line. A particularly nice use case is when you write scripts that expect "subcommand" arguments, like

    $ foo.sh bar baz
and wish to keep track of the available subcommands in the help documentation. Simply collect all your subcommands under the heading "## Subcommands" and stick a funs call in your documentation:

    usage=$(cat 
    Subcommands: $(funs Subcommands)
    USAGE
    )
The sed one-liner above uses the oft-ignored "hold space" which lets you store data that persists between lines. Here's the same sed but expanded with comments:

    funs(){ sed -n '/^## /h  # Store header line in hold space
        x               # Swap out current line with header in hold space.
        /'"$1"'/{       # Run block if last encountered header matches $1
            x           # Return to processing current line (instead of header)
            s/^\(\w\+\)().*/\1/p    # Print function names
            x           # Whether or not this block runs, we want to return to
                        # processing the current line. If the block does not
                        # run, then the hold space contains our current line
                        # with the active line being our header. So we must
        }               # return to that state as whell when the block is run.
        x               # Restore current line from hold space' "$0"
    }

Re: Help Message for Shell Scripts

#98
post #59

You can also use a "here document" help() { cat Options: Input file to read. Output file to write. Use '-' for stdout. -h Show this message. EOH } If the indentation bugs you, you can use a simpler sed trick to remove leading space so that you can indent it as desired: help() { sed -e 's/ //' Options: Input file to read. Output file to write. Use '-' for stdout. -h Show this message. EOH }

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.

This is one (useful!) interpretation of "code should be self-documenting". Just put the documentation into strings.

Re: Help Message for Shell Scripts

#99
post #70
post #20

Earlier quoted context omitted.

But handling args isn't that bad in bash. while [[ $# -gt 0 ]]; do case "$1" in -h|--help) do_help exit ;; -v|--version) do_version exit ;; -d|--debug) debug=true shift ;; -a|--arg) arg_value=$2 shift 2 ;; esac done

import argparse parser = argparse.ArgumentParser() parser.add_argument('-v','--version',action='version', version='demo',help='Print version information') parser.add_argument('-d','--debug', help='Enable Debug Mode') parser.add_argument('a','arg', help="Argument Documentation") args = parser.parse_args() Personally I feel like this is more readable code, gets me better validation, and help docs for "free". That's the…

Elegant, but then it's no longer a basic shell-script as it requires python installed.

If you can live with additional dependencies, then I like the node [1] commander package, which is very readable and nice to work with in my opinion.

        #!/usr/bin/env node
        const { program } = require('commander');

        program
          .command('clone  [destination]')
          .description('clone a repository')
          .action((source, destination) => {
            console.log('clone command called');
          });
It also automatically generates the --help output for ./script -h

[1] https://github.com/tj/commander.js/

Post reply on HN