# Argbash - Bash Argument Parser Generator Argbash is a code generator that creates robust argument parsing logic for Bash scripts. Instead of being a runtime library, it generates tailor-made parsing code based on your specifications, eliminating the need for external dependencies during script execution. The tool allows you to declare your script's expected arguments through simple macros embedded in comments, then generates clean, readable Bash code that handles all aspects of argument parsing including validation, defaults, and help messages. Argbash supports all common argument types including positional arguments with defaults, single-valued and boolean optional arguments, incremental and repeated arguments, and action arguments like --help and --version. The generated code is portable across all platforms with Bash 3.0 or higher, and can produce various output formats including Bash scripts, POSIX-compliant scripts, bash completion files, docopt-compliant help messages, and man pages. The tool's parsing definitions stay embedded in the script itself, making it easy to regenerate the parsing logic when requirements change. ## Core Command-Line Tools ### argbash - Main Code Generator Generates argument parsing code from template files containing Argbash macro definitions. ```bash # Generate a bash script from a template argbash myfile.m4 -o myfile.sh # Update a script in-place argbash myfile.sh --in-place # Generate with inline comments explaining the code argbash myfile.m4 -o myfile.sh --commented # Generate POSIX-compliant script argbash myfile.m4 -o myfile.sh --type posix-script # Generate bash completion file argbash myfile.m4 -o myfile-completion.sh --type completion # Generate man page definition argbash myfile.m4 -o myfile.1 --type manpage # Generate parsing library (strips user content) argbash myfile.m4 -o myfile-lib.sh --strip user-content # Search for wrapped scripts in multiple directories argbash myfile.m4 -o myfile.sh -I ./lib -I ./vendor # Output to stdout argbash myfile.m4 ``` ### argbash-init - Template Generator Creates initial template files with argument definitions, eliminating the need to write templates from scratch. ```bash # Generate basic template to stdout argbash-init # Generate template with output filename argbash-init myscript.m4 # Generate with positional and optional arguments argbash-init myscript.m4 --pos filename --opt output --opt-bool verbose # Generate with hints in comments argbash-init myscript.m4 --hints --pos input --opt-bool debug # Generate with separate parsing library (managed mode) argbash-init myscript.m4 --separate --pos file --opt config # Generate with fully decoupled parsing (decoupled mode) argbash-init myscript.m4 -s -s --pos input # Generate minimal feature set argbash-init myscript.m4 --mode minimal --pos file # Generate full feature set argbash-init myscript.m4 --mode full --opt-bool verbose ``` ## Argument Type Macros ### ARG_POSITIONAL_SINGLE - Single Positional Argument Defines a required positional argument, or optional if a default value is provided. ```bash #!/usr/bin/env bash # ARG_POSITIONAL_SINGLE([filename], [The file to process], []) # ARG_POSITIONAL_SINGLE([output], [Output file], [output.txt]) # ARG_HELP([File processor]) # ARGBASH_GO # [ <-- needed because of Argbash echo "Processing file: $_arg_filename" echo "Output to: $_arg_output" # Process the file if [ -f "$_arg_filename" ]; then cat "$_arg_filename" > "$_arg_output" else echo "Error: File not found" >&2 exit 1 fi # ] <-- needed because of Argbash ``` ### ARG_POSITIONAL_MULTI - Multiple Positional Arguments Defines a fixed number of positional arguments with optional defaults for trailing arguments. ```bash #!/usr/bin/env bash # ARG_POSITIONAL_MULTI([coords], [X Y Z coordinates], [3], [], [], [0]) # ARG_HELP([3D point processor]) # ARGBASH_GO # [ <-- needed because of Argbash # Access array elements (0-indexed) echo "X: ${_arg_coords[0]}" echo "Y: ${_arg_coords[1]}" echo "Z: ${_arg_coords[2]}" # Calculate distance from origin x=${_arg_coords[0]} y=${_arg_coords[1]} z=${_arg_coords[2]} distance=$(echo "scale=2; sqrt($x*$x + $y*$y + $z*$z)" | bc) echo "Distance from origin: $distance" # ] <-- needed because of Argbash ``` ### ARG_POSITIONAL_INF - Variable Number of Positional Arguments Defines an argument that accepts unlimited positional values with a specified minimum. ```bash #!/usr/bin/env bash # ARG_POSITIONAL_INF([files], [Files to process], [1]) # ARG_OPTIONAL_BOOLEAN([verbose], [v], [Verbose output]) # ARG_HELP([Batch file processor]) # ARGBASH_GO # [ <-- needed because of Argbash echo "Processing ${#_arg_files[@]} files..." for file in "${_arg_files[@]}"; do if [ -f "$file" ]; then [ "$_arg_verbose" = "on" ] && echo "Processing: $file" wc -l "$file" else echo "Warning: $file not found" >&2 fi done # ] <-- needed because of Argbash ``` ### ARG_OPTIONAL_SINGLE - Optional Argument with Value Defines an optional argument that accepts a single value. ```bash #!/usr/bin/env bash # ARG_OPTIONAL_SINGLE([config], [c], [Configuration file path], [/etc/app.conf]) # ARG_OPTIONAL_SINGLE([port], [p], [Port number], [8080]) # ARG_POSITIONAL_SINGLE([command], [Command to execute]) # ARG_HELP([Application launcher]) # ARGBASH_GO # [ <-- needed because of Argbash echo "Loading config from: $_arg_config" echo "Port: $_arg_port" echo "Executing command: $_arg_command" # Check if config file exists if [ ! -f "$_arg_config" ]; then echo "Warning: Config file not found, using defaults" >&2 fi # Start application case "$_arg_command" in start) echo "Starting application on port $_arg_port" ;; stop) echo "Stopping application" ;; *) echo "Unknown command: $_arg_command" >&2 exit 1 ;; esac # ] <-- needed because of Argbash ``` ### ARG_OPTIONAL_BOOLEAN - Boolean Flag Argument Defines a boolean flag that is either on or off. ```bash #!/usr/bin/env bash # ARG_OPTIONAL_BOOLEAN([debug], [d], [Enable debug mode], [off]) # ARG_OPTIONAL_BOOLEAN([force], [f], [Force operation], [off]) # ARG_POSITIONAL_SINGLE([operation], [Operation to perform]) # ARG_HELP([System utility]) # ARGBASH_GO # [ <-- needed because of Argbash [ "$_arg_debug" = "on" ] && set -x echo "Operation: $_arg_operation" echo "Debug mode: $_arg_debug" echo "Force mode: $_arg_force" if [ "$_arg_force" = "off" ]; then echo "Are you sure? (y/n)" read -r answer [ "$answer" != "y" ] && exit 0 fi # Perform operation echo "Executing $_arg_operation..." # ] <-- needed because of Argbash ``` ### ARG_OPTIONAL_INCREMENTAL - Incrementing Flag Defines an argument that counts how many times it was specified (useful for verbosity levels). ```bash #!/usr/bin/env bash # ARG_OPTIONAL_INCREMENTAL([verbose], [v], [Increase verbosity level], [0]) # ARG_POSITIONAL_SINGLE([input], [Input file]) # ARG_HELP([File analyzer with verbosity levels]) # ARGBASH_GO # [ <-- needed because of Argbash echo "Verbosity level: $_arg_verbose" # Set log level based on verbosity if [ $_arg_verbose -eq 0 ]; then log_level="ERROR" elif [ $_arg_verbose -eq 1 ]; then log_level="WARNING" elif [ $_arg_verbose -eq 2 ]; then log_level="INFO" else log_level="DEBUG" fi echo "Log level: $log_level" # Process with appropriate verbosity [ $_arg_verbose -ge 1 ] && echo "Reading file: $_arg_input" [ $_arg_verbose -ge 2 ] && echo "File size: $(wc -c < "$_arg_input") bytes" [ $_arg_verbose -ge 3 ] && echo "File type: $(file -b "$_arg_input")" # ] <-- needed because of Argbash ``` ### ARG_OPTIONAL_REPEATED - Repeated Argument Values Defines an argument that can be specified multiple times, accumulating values in an array. ```bash #!/usr/bin/env bash # ARG_OPTIONAL_REPEATED([include], [I], [Include directories], ['/usr/include' '/usr/local/include']) # ARG_OPTIONAL_REPEATED([define], [D], [Preprocessor definitions], []) # ARG_POSITIONAL_SINGLE([source], [Source file to compile]) # ARG_HELP([C compiler wrapper]) # ARGBASH_GO # [ <-- needed because of Argbash echo "Include directories:" for dir in "${_arg_include[@]}"; do echo " $dir" done echo "Definitions:" for def in "${_arg_define[@]}"; do echo " $def" done # Build compiler command cmd="gcc" for dir in "${_arg_include[@]}"; do cmd="$cmd -I$dir" done for def in "${_arg_define[@]}"; do cmd="$cmd -D$def" done cmd="$cmd $_arg_source" echo "Compiler command: $cmd" # Execute: eval "$cmd" # ] <-- needed because of Argbash ``` ### ARG_OPTIONAL_ACTION - Action Argument Defines an argument that executes code and exits when specified. ```bash #!/usr/bin/env bash # ARG_OPTIONAL_ACTION([list-modes], [l], [List available modes], [echo "Modes: fast, normal, slow"; exit 0]) # ARG_OPTIONAL_SINGLE([mode], [m], [Processing mode], [normal]) # ARG_POSITIONAL_SINGLE([input], [Input file]) # ARG_HELP([File processor with modes]) # ARGBASH_GO # [ <-- needed because of Argbash echo "Processing $_arg_input in $_arg_mode mode" case "$_arg_mode" in fast) echo "Using fast mode with reduced accuracy" ;; normal) echo "Using normal mode" ;; slow) echo "Using slow mode with maximum accuracy" ;; *) echo "Invalid mode: $_arg_mode" >&2 exit 1 ;; esac # ] <-- needed because of Argbash ``` ## Special Argument Macros ### ARG_HELP - Help Message Generates --help argument with customizable help text. ```bash #!/usr/bin/env bash # ARG_POSITIONAL_SINGLE([file], [File to process]) # ARG_OPTIONAL_SINGLE([format], [f], [Output format], [text]) # ARG_OPTIONAL_BOOLEAN([color], [c], [Enable colored output]) # ARG_HELP([Document formatter], [Formats documents in various output formats.\nSupports text, html, and markdown formats.\n\nExamples:\n formatter input.txt -f html\n formatter input.txt --color]) # ARGBASH_GO # [ <-- needed because of Argbash echo "Formatting file: $_arg_file" echo "Format: $_arg_format" [ "$_arg_color" = "on" ] && echo "Using colored output" # ] <-- needed because of Argbash ``` ### ARG_VERSION and ARG_VERSION_AUTO - Version Information Generates --version argument with version information. ```bash #!/usr/bin/env bash # Define version version="1.2.3" # ARG_POSITIONAL_SINGLE([file], [File to process]) # ARG_VERSION_AUTO([1.2.3], [Copyright 2024 Example Corp]) # ARG_HELP([File processor]) # ARGBASH_GO # [ <-- needed because of Argbash echo "Processing file: $_arg_file" echo "Running version: $version" # ] <-- needed because of Argbash ``` ## Typing and Validation Macros ### ARG_TYPE_GROUP - Built-in Type Validation Validates argument values against built-in types like integers and floats. ```bash #!/usr/bin/env bash # ARG_OPTIONAL_SINGLE([port], [p], [Server port], [8080]) # ARG_OPTIONAL_SINGLE([timeout], [t], [Timeout in seconds], [30]) # ARG_OPTIONAL_SINGLE([ratio], [r], [Ratio value], [0.5]) # ARG_TYPE_GROUP([pint], [PORT], [port]) # ARG_TYPE_GROUP([nnint], [SECONDS], [timeout]) # ARG_TYPE_GROUP([float], [RATIO], [ratio]) # ARG_HELP([Network client with type validation]) # ARGBASH_GO # [ <-- needed because of Argbash echo "Connecting to localhost:$_arg_port" echo "Timeout: $_arg_timeout seconds" echo "Ratio: $_arg_ratio" # Argument values are guaranteed to be valid at this point # port is a positive integer, timeout is non-negative, ratio is a float # ] <-- needed because of Argbash ``` ### ARG_TYPE_GROUP_SET - Restricted Value Set Restricts argument values to a specific set of allowed values. ```bash #!/usr/bin/env bash # ARG_OPTIONAL_SINGLE([log-level], [l], [Logging level], [info]) # ARG_OPTIONAL_SINGLE([environment], [e], [Deployment environment], [dev]) # ARG_TYPE_GROUP_SET([loglevel], [LEVEL], [log-level], [debug,info,warning,error], [index]) # ARG_TYPE_GROUP_SET([env], [ENV], [environment], [dev,staging,prod], [index]) # ARG_POSITIONAL_SINGLE([command], [Command to execute]) # ARG_HELP([Application with restricted values]) # ARGBASH_GO # [ <-- needed because of Argbash echo "Log level: $_arg_log_level (index: $_arg_log_level_index)" echo "Environment: $_arg_environment (index: $_arg_environment_index)" # Use index for numeric comparisons if [ $_arg_log_level_index -ge 3 ]; then echo "Error logging enabled" fi # Configure based on environment case $_arg_environment_index in 0) echo "Development mode: debug enabled" ;; 1) echo "Staging mode: metrics enabled" ;; 2) echo "Production mode: optimizations enabled" ;; esac # ] <-- needed because of Argbash ``` ## Convenience and Utility Macros ### DEFINE_SCRIPT_DIR - Script Directory Variable Makes the script's directory available in a variable for loading relative resources. ```bash #!/usr/bin/env bash # DEFINE_SCRIPT_DIR() # ARG_OPTIONAL_SINGLE([config], [c], [Config file relative to script], [config.conf]) # ARG_HELP([Application with relative config loading]) # ARGBASH_GO # [ <-- needed because of Argbash # Load config relative to script location config_path="$script_dir/$_arg_config" echo "Loading config from: $config_path" if [ -f "$config_path" ]; then source "$config_path" echo "Config loaded successfully" else echo "Config file not found at $config_path" >&2 exit 1 fi # Load library from same directory source "$script_dir/lib/utils.sh" # ] <-- needed because of Argbash ``` ### ARGBASH_WRAP - Script Wrapping Inherits arguments from another Argbash-powered script for easy wrapper creation. ```bash # File: process-single.m4 #!/usr/bin/env bash # ARG_OPTIONAL_SINGLE([quality], [q], [Quality level], [normal]) # ARG_OPTIONAL_BOOLEAN([compress], [c], [Enable compression]) # ARG_POSITIONAL_SINGLE([input], [Input file]) # ARG_HELP([Process single file]) # ARGBASH_GO # File: process-batch.m4 #!/usr/bin/env bash # ARGBASH_WRAP([process-single], [input]) # ARG_POSITIONAL_INF([files], [Files to process], [1]) # ARG_HELP([Batch file processor]) # DEFINE_SCRIPT_DIR() # ARGBASH_GO # [ <-- needed because of Argbash # Inherits --quality and --compress from process-single # The input argument is excluded from wrapping echo "Processing ${#_arg_files[@]} files" for file in "${_arg_files[@]}"; do echo "Processing: $file" # Pass inherited arguments to wrapped script "$script_dir/process-single.sh" "${_args_process_single_opt[@]}" "$file" done # ] <-- needed because of Argbash ``` ### ARG_USE_ENV - Environment Variable Declaration Declares environment variable usage with defaults and help text. ```bash #!/usr/bin/env bash # ARG_USE_ENV([EDITOR], [vim], [The preferred text editor]) # ARG_USE_ENV([PAGER], [less], [The preferred pager]) # ARG_POSITIONAL_SINGLE([file], [File to edit]) # ARG_HELP([File editor wrapper]) # ARGBASH_GO # [ <-- needed because of Argbash echo "Using editor: $EDITOR" echo "Using pager: $PAGER" # Open file with configured editor "$EDITOR" "$_arg_file" # Show file with pager "$PAGER" "$_arg_file" # ] <-- needed because of Argbash ``` ### ARG_LEFTOVERS - Collect Remaining Arguments Collects unrecognized arguments for passing to wrapped commands. ```bash #!/usr/bin/env bash # ARG_OPTIONAL_BOOLEAN([dry-run], [n], [Show command without executing]) # ARG_OPTIONAL_SINGLE([timeout], [t], [Execution timeout], [300]) # ARG_LEFTOVERS([Arguments to pass to wrapped command]) # ARG_HELP([Command wrapper with timeout]) # ARGBASH_GO # [ <-- needed because of Argbash cmd="timeout $_arg_timeout" # Append all leftover arguments for arg in "${_arg_leftovers[@]}"; do cmd="$cmd $arg" done if [ "$_arg_dry_run" = "on" ]; then echo "Would execute: $cmd" else echo "Executing: $cmd" eval "$cmd" fi # ] <-- needed because of Argbash ``` ## Advanced Configuration Macros ### ARGBASH_SET_DELIM - Option-Value Delimiter Controls how option values can be separated from their options. ```bash #!/usr/bin/env bash # ARGBASH_SET_DELIM([=]) # ARG_OPTIONAL_SINGLE([output], [o], [Output file]) # ARG_OPTIONAL_SINGLE([format], [f], [Output format]) # ARG_HELP([Tool with equals-only delimiter]) # ARGBASH_GO # [ <-- needed because of Argbash # Valid: --output=file.txt --format=json # Invalid: --output file.txt (treated as positional) # Invalid: -o file.txt (treated as positional) echo "Output: $_arg_output" echo "Format: $_arg_format" # ] <-- needed because of Argbash ``` ### ARG_OPTION_STACKING - Short Option Grouping Controls whether short options can be stacked together. ```bash #!/usr/bin/env bash # ARG_OPTION_STACKING([getopts]) # ARG_OPTIONAL_BOOLEAN([verbose], [v], [Verbose output]) # ARG_OPTIONAL_BOOLEAN([quiet], [q], [Quiet mode]) # ARG_OPTIONAL_BOOLEAN([force], [f], [Force operation]) # ARG_HELP([Tool with option stacking]) # ARGBASH_GO # [ <-- needed because of Argbash # Can use: -vqf instead of -v -q -f # Supports getopts-style option grouping echo "Verbose: $_arg_verbose" echo "Quiet: $_arg_quiet" echo "Force: $_arg_force" # ] <-- needed because of Argbash ``` ### ARG_RESTRICT_VALUES - Value Validation Mode Restricts what can be passed as argument values to prevent common errors. ```bash #!/usr/bin/env bash # ARG_RESTRICT_VALUES([no-local-options]) # ARG_OPTIONAL_SINGLE([input], [i], [Input file]) # ARG_OPTIONAL_SINGLE([output], [o], [Output file]) # ARG_POSITIONAL_SINGLE([command], [Command to execute]) # ARG_HELP([Tool with value restrictions]) # ARGBASH_GO # [ <-- needed because of Argbash # Prevents: script --input --output file.txt # (--output would be rejected as value for --input) echo "Input: $_arg_input" echo "Output: $_arg_output" echo "Command: $_arg_command" # ] <-- needed because of Argbash ``` ## Complete Working Example ### File Size Reporter with Full Validation A practical script demonstrating multiple Argbash features working together. ```bash #!/usr/bin/env bash # DEFINE_SCRIPT_DIR() # ARG_POSITIONAL_SINGLE([filename], [File to analyze]) # ARG_OPTIONAL_SINGLE([unit], [u], [Unit for size (b/k/M/G)], [k]) # ARG_OPTIONAL_BOOLEAN([verbose], [v], [Verbose output], [off]) # ARG_OPTIONAL_BOOLEAN([human], [H], [Human-readable format]) # ARG_OPTIONAL_SINGLE([precision], [p], [Decimal precision], [2]) # ARG_TYPE_GROUP_SET([units], [UNIT], [unit], [b,k,M,G]) # ARG_TYPE_GROUP([nnint], [PRECISION], [precision]) # ARG_VERSION_AUTO([1.0.0]) # ARG_HELP([File Size Reporter], [Analyzes and reports file sizes in various units.\n\nSupports bytes (b), kibibytes (k), mebibytes (M), and gibibytes (G).\n\nExample:\n filesize document.pdf -u M -v\n filesize image.jpg --human]) # ARGBASH_GO # [ <-- needed because of Argbash # Validate file exists if [ ! -f "$_arg_filename" ]; then echo "Error: File '$_arg_filename' not found" >&2 exit 1 fi # Get size in bytes size_bytes=$(wc -c < "$_arg_filename") [ "$_arg_verbose" = "on" ] && echo "File: $_arg_filename" [ "$_arg_verbose" = "on" ] && echo "Size in bytes: $size_bytes" # Calculate size in requested unit case "$_arg_unit" in b) size=$size_bytes unit_name="bytes" ;; k) size=$(echo "scale=$_arg_precision; $size_bytes / 1024" | bc) unit_name="KiB" ;; M) size=$(echo "scale=$_arg_precision; $size_bytes / 1048576" | bc) unit_name="MiB" ;; G) size=$(echo "scale=$_arg_precision; $size_bytes / 1073741824" | bc) unit_name="GiB" ;; esac # Output result if [ "$_arg_human" = "on" ]; then printf "File size: %s %s\n" "$size" "$unit_name" [ "$_arg_verbose" = "on" ] && printf "Precision: %d decimals\n" "$_arg_precision" else echo "$size" fi # ] <-- needed because of Argbash ``` ## Summary and Integration Argbash revolutionizes Bash script argument parsing by generating custom parsing code instead of requiring runtime libraries. The generated code is self-contained, portable, and requires no external dependencies beyond Bash itself. This approach results in faster script execution and eliminates version compatibility concerns that plague library-based solutions. The tool's macro-based API is intuitive and well-documented, supporting everything from simple boolean flags to complex repeated arguments with type validation. Integration into existing projects is straightforward: add macro comments to your script, run argbash to generate the parsing code, and access arguments through predefined variables following the `_arg_` pattern. The tool supports multiple workflow patterns including inline parsing code for simplicity, separated parsing libraries for cleaner organization, and script wrapping for building command hierarchies. Combined with features like automatic help generation, bash completion, man page output, and comprehensive type validation, Argbash provides a complete solution for professional-grade Bash script argument handling that scales from simple utilities to complex command-line applications.