News for hackers. Stuff that matters.
Re:Bash functions are better than I thought by MereInterest on Sunday October 31, 2021 @02:50PM (#29059302)
To have variable typos result in errors with `set -u`, then expand an array that is defined but may be empty, I need write it as `${ARRAY[@]+"${ARRAY[@]}"`. (Further explanation: https://stackoverflow.com/questions/7577052/bash-empty-array...) But maybe bash arrays are too new a feature, and should be avoided, so let's look at something simpler, like command-line arguments.

Parsing command-line arguments is easy, but parsing them correctly is ridiculously hard. `getopts` doesn't handle long flags, so it's out. `getopt` doesn't handle arguments with spaces in them, unless you have a version with non-standard extensions, so it's out. You're left with manual parsing, and it's a royal pain to make sure you handle every expected case (short/long flags, clusters of short flags, trailing arguments to be passed through to a subprocess, short/long options whose value is in the next argument, long options whose value is after an equals sign, and several others I'm probably forgetting about). And this is just to get the arguments into your script, before you actually do anything with it.

I agree that bash has effective idioms, and learning those idioms can make scripts easier to write. I strongly disagree that bash is "as maintainable as anything else", and scripts beyond a few hundred lines should be rewritten before they can continue growing.

Re:Bash functions are better than I thought by databasher on Sunday October 31, 2021 @11:40PM (#29062791)
Bash `getopts` handles short and long arguments gnu-style without any problem. The following code handles args like "-h", "-i $input-file", "-i$input-file", "--in=$input-file", and "--help":

  while getopts :i:h-: option
  do case $option in
         # accept -i $input-file, -i$input-file
         i ) input_file=$OPTARG;;
         h ) print_help;;
         - ) case $OPTARG in
                 help ) print_help;;
                 help=* ) echo "Option has unexpected argument: ${OPTARG%%=*}" >&2; exit 1;;
                 in=* ) input_file=${OPTARG##*=};;
                 in ) echo "Option missing argument: $OPTARG" >&2; exit 1;;
                 * ) echo "Bad option $OPTARG" >&2; exit 1;;
             esac;;
         '?' ) echo "Unknown option $OPTARG" >&2; exit 1;;
         : ) echo "Option missing argument: $OPTARG" >&2; exit 1;;
         * ) echo "Bad state in getopts" >&2; exit 1;;
     esac
  done
  shift $((OPTIND-1))
Re:Bash functions are better than I thought by drran on Sunday October 31, 2021 @06:57PM (#29061295)
You can use bash-modules arguments library to generate argument parser for you.
Re:Bash functions are better than I thought by MereInterest on Sunday October 31, 2021 @07:25PM (#29061463)
Thank you, I haven't heard of that one before. However, all the examples look like it gets called as an external library, which would either need to be distributed with a script, or to already be installed by a user.

Is there a feature I'm not seeing that would generate an argument parser without external dependencies?

Re:Bash functions are better than I thought by drran on Monday November 01, 2021 @05:24AM (#29064527)
Yes, arguments::generate_parser function. Install bash-modules, then run `. import.sh log arguments`, then call `arguments::generate_parser '--foo)FOO;String'` , and it will generate function with parser, which include parser for foo option for both `--foo VALUE` and `--foo=VALUE`:

  ...
  
        --foo)
          FOO="${2:?ERROR: String value is required for \"-f|--foo\" option. See --help for details.}"
          shift 2
        ;;
        --foo=*)
          FOO="${1#*=}"
          shift 1
        ;;
  ...