Skip to content

Bug Report: gengetoptions embed fails with "parameter not set or null" when using setup - #67

@yumetodo

Description

@yumetodo

============ STEP1: Issue Description ============

Issue Details

  • When using setup - in parser definition (to omit restargs variable as documented), gengetoptions embed command fails with error: /path/to/gengetoptions: 69: _rest: parameter not set or null
  • According to References.md documentation, specifying - should allow omitting the restargs variable, but the implementation does not handle this case correctly.

Expected Behavior

Steps to Reproduce

  • Reproduction rate: 100% (tested 3/3 times)
  • Reproduction steps:
    1. Create a shell script with parser definition using setup - (see test-minimal.sh below)
    2. Run command: gengetoptions embed --overwrite test-minimal.sh
    3. Observe the error: /path/to/gengetoptions: 69: _rest: parameter not set or null

Environment

Environment Information
  • Software
    • getoptions version: 3.3.2
    • gengetoptions version: 3.3.2
  • System
    • OS: Ubuntu 22.04.5 LTS(Linux 5.15.0-164-generic)
    • Shell: GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)

Minimal Test Case

test-minimal.sh:

#!/bin/sh
# Minimal test case to reproduce the issue with setup -

# @getoptions
parser_definition() {
    setup - help:usage -- "Usage: test-minimal.sh [OPTIONS]" ''
    msg -- 'Options:'
    param MODE --mode init:=default -- "Operation mode"
    disp :usage -h --help
}
# @end

# @gengetoptions parser -i parser_definition parse
# (Empty - code should be generated here by gengetoptions embed)
# @end

eval "$(getoptions parser_definition parse)"
parse "$@"
eval "set -- $REST"

echo "MODE: $MODE"

Command to reproduce:

$ gengetoptions embed --overwrite test-minimal.sh
/home/user/.local/bin/gengetoptions: 69: _rest: parameter not set or null

Additional Notes

  • The same script works correctly when using setup REST instead of setup -
  • This appears to be a discrepancy between documentation and implementation

============ STEP2: Root Cause Analysis ============

Root Cause

  • In /path/to/getoptions line 68, when the first argument to _setup() is -, the condition [ "${1#-}" ] evaluates to false (empty string), so _rest=$1 is never executed, leaving _rest unset.
  • However, line 80 uses ${_rest:?} which requires _rest to be set, causing the "parameter not set or null" error.
  • This is triggered by line 5: set -eu (specifically the -u option which treats unset variables as errors).

Relevant code in getoptions (lines 67-80):

_setup() {
    [ "${1#-}" ] && _rest=$1  # Line 68: Does NOT set _rest when $1 is "-"
    while loop "$@" && shift; do kv "$1" _; done
}
# ... (lines 71-79)
_0 "${_rest:?}=''"  # Line 80: Requires _rest to be set

Conditions for Issue Occurrence

  • Using setup - in parser definition (attempting to omit restargs as documented)
  • Running gengetoptions embed or any command that invokes the getoptions code generation

Workaround (How to avoid the issue)

  • Workaround procedure:
    1. Always specify a restargs variable name (e.g., REST) instead of using -
    2. Change setup - to setup REST in the parser definition
    3. Example: setup REST help:usage -- "Usage: example.sh [OPTIONS]" ''

Recovery Method (How to fix after encountering the issue)

  • Recovery procedure:
    1. Open the affected shell script file
    2. Locate the parser_definition() function
    3. Change the setup line from setup - to setup REST (or any other valid variable name)
    4. Re-run the gengetoptions embed --overwrite command
    5. The command should now complete successfully

Additional Investigation Notes

  • This appears to be an implementation bug in getoptions v3.3.2
  • The documentation (References.md) clearly states that - can be used to omit restargs, but the implementation does not properly support this
  • A potential fix would be to modify line 80 in getoptions to conditionally generate the restargs initialization:
    # Current (buggy):
    _0 "${_rest:?}=''"
    
    # Suggested fix:
    [ "$_rest" ] && _0 "$_rest=''"
  • This would require updating the subsequent code that references $_rest to handle the case where it may be unset

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions