ArguBASH is a declarative argument parser for Bash scripts that makes command-line option handling easy, clean, consistent, and powerful. It provides a structured way to define script arguments with defaults and help text, eliminating the need to write complex argument parsing logic for each script.
A key benefit of ArguBASH is that it can create completely self-contained scripts with no external dependencies. The argument parser is embedded directly within your script, ensuring your scripts will run reliably anywhere Bash is available, without requiring users to install additional packages or libraries.
To quickly implement ArguBASH in your script:
#!/bin/bash
#################################################################
# ARGUMENT DEFINITION
ARGS_AND_DEFAULTS=(
# Source directory for operations
source_dir="$(pwd)"
# Enable verbose output
verbose=false
)
# END of ARGUMENT DEFINITION
#################################################################
# Copy the ARGUMENT PARSER section from ArguBASH-template.sh here
# After the parser, your script can use the variables directly
if [[ ${verbose} == true ]]; then
echo "Operating in verbose mode on directory: ${source_dir}"
fi
# Your script logic here...
- Define your arguments and defaults in the
ARGS_AND_DEFAULTS
array - Copy the ARGUMENT PARSER section from
ArguBASH-template.sh
- Use your arguments as standard Bash variables in your script
- (Optional) Enable tab completion for a better interactive experience
- Completely Self-Contained: Creates standalone scripts with no external dependencies
- Declarative Argument Definition: Define arguments and their defaults in a simple array structure
- Automatic Help Generation: Comments become help text automatically
- Basic Argument Validation: Validates argument names and structure (not values)
- Environment Variable Support: Default values can be overridden by environment variables
- Command-line/Variable Name Conversion: Automatic conversion between command-line options with dashes (
--vm-sku
) and script variables with underscores (vm_sku
) - Positional Arguments Support: Optionally capture remaining arguments with support for the
--
delimiter - Tab Completion:
- Supports Bash tab completion for all defined arguments
- Enhanced Zsh completion that displays help text descriptions and default values directly in the completion menu, leveraging ArguBASH's declarative structure
To use ArguBASH in your scripts, copy the argument parser section from the ArguBASH-template.sh
file into your script. The section is clearly marked with:
##################################################################
# ARGUMENT PARSER
...
# END of ARGUMENT PARSER
##################################################################
This approach ensures your script is completely self-contained with no external dependencies. Users won't need to install anything special to run your script—just Bash itself.
The typical structure of an ArguBASH-powered script is:
- Script header (shebang, copyright, description)
- ARGUMENT DEFINITION section with your
ARGS_AND_DEFAULTS
array - ARGUMENT PARSER section copied from
ArguBASH-template.sh
- Your custom script logic that uses the defined variables
Define your arguments in the ARGS_AND_DEFAULTS
array:
ARGS_AND_DEFAULTS=(
# The directory to operate on, defaults to current directory
dir="$(pwd)"
# The verbosity level of script output
# 0 = minimal output (quiet)
# 1 = standard logging (recommended)
# 2 = detailed debugging output
verbosity=1
# Run in simulation mode without making actual changes
dry_run=false
)
Notes:
- Comments above each argument are used as help text
- Only comments starting with
#
(hash and space) are used for help text - Comments starting with
##
are for script maintainers and won't appear in help
ArguBASH supports positional arguments, which are arguments that aren't associated with a specific named parameter. These are commonly used for file paths, commands, or other values that make sense as primary inputs to your script.
To enable positional arguments in your script, set EXTRA_ARGS=true
at the beginning of your ARGUMENT DEFINITION section:
# Enable collection of positional arguments
EXTRA_ARGS=true
# Array to hold the positional arguments
extra_args=()
When enabled, ArguBASH collects positional arguments in two ways:
-
Implicit positional arguments: Any command-line argument that doesn't start with
--
and isn't a value for a named parameter is treated as a positional argument. -
Explicit positional arguments using the standard
--
delimiter: Following the universal Unix/Linux convention, any arguments that appear after a standalone--
delimiter are treated as positional arguments, even if they start with dashes. This is critical when you need to pass arguments that begin with dashes (which would normally be interpreted as options) as actual values.
The --
delimiter (end-of-options marker) is an established standard across Unix/Linux tools and is especially important when:
- Working with filenames or paths that begin with a dash
- such as
rm -- *
in case the files include a file with a leading-
- such as
- Handling arguments that might be interpreted as options
All positional arguments are stored in the extra_args
array, which you can access in your script logic.
./my-script.sh --verbose true file1.txt file2.txt
In this example, file1.txt
and file2.txt
are collected as positional arguments.
./my-script.sh --verbose true -- foo --output-file report.txt
Here, --output-file
and report.txt
are treated as positional arguments because they appear after the --
delimiter, even though --output-file
looks like a named parameter to the script but in this case is really a parameter to the foo
thing (potentially a command your script wrappers).
You can access the positional arguments using standard bash array operations:
# Check if there are any positional arguments
if [[ ${#extra_args[@]} -gt 0 ]]; then
# Access the first positional argument
first_arg="${extra_args[0]}"
# Iterate through all positional arguments
for arg in "${extra_args[@]}"; do
echo "Processing: ${arg}"
done
# Get the total number of positional arguments
num_args=${#extra_args[@]}
echo "Received ${num_args} positional arguments"
fi
Positional arguments are useful for:
- File or directory paths that are primary inputs to your script, especially if there can be an arbitrary number of them.
- Wrapped commands - when your script acts as a wrapper for other commands and their options
- Simplifying the interface when parameters have a natural, expected order such as
cp fromfile tofile
does.
For important configuration options that might be missed, named parameters (with --name value
syntax) are generally more self-documenting and should be preferred.
Your script will automatically support:
./your-script.sh --argument value [--help|-h] [positional args]
For example:
./your-script.sh --dir /some/path --verbosity 2
-h
shows a brief summary of arguments--help
shows detailed help with all comments
Example brief help output (-h
):
Usage: ./example-command.sh [--<override> value] [--help|-h] <positional args>
--dir default: /workspace/src
--verbosity default: 1
--dry-run default: false
--parallel default: 4
-- pass remaining arguments
--help for more complete help
Example detailed help output (--help
):
Usage: ./example-command.sh [--<override> value] [--help|-h] <positional args>
--dir default: /workspace/src
original: "$(pwd)"
The directory to operate on, defaults to current directory
------------------------------------------------------
--verbosity default: 1
Verbosity level (0=quiet, 1=normal, 2=verbose)
Controls how much information is displayed during execution
------------------------------------------------------
--dry-run default: false
Run in simulation mode without making changes
Set to true to see what would happen without actual execution
------------------------------------------------------
--parallel default: 4
Maximum number of parallel operations
Higher values may improve performance but use more resources
------------------------------------------------------
-- pass remaining arguments
-h for quick argument summary
Here's a simple example script (example-command.sh):
#!/bin/bash
#################################################################
# ARGUMENT DEFINITION
#
EXTRA_ARGS=true
extra_args=()
ARGS_AND_DEFAULTS=(
# The directory to operate on, defaults to current directory
dir="$(pwd)"
# Verbosity level (0=quiet, 1=normal, 2=verbose)
# Controls how much information is displayed during execution
verbosity=1
# Run in simulation mode without making changes
# Set to true to see what would happen without actual execution
dry_run=false
# Maximum number of parallel operations
# Higher values may improve performance but use more resources
parallel=4
)
# END of ARGUMENT DEFINITION
##################################################################
# Copy the ARGUMENT PARSER section from ArguBASH-template.sh here
# Your script logic starts here
echo "This is a no-op example command that just shows the arguments:"
echo " Directory: ${dir}"
echo " Verbosity: ${verbosity}"
echo " Dry run: ${dry_run}"
echo " Parallel: ${parallel}"
if [[ ${#extra_args[@]} -gt 0 ]]; then
echo " Extra args:"
for xtra in "${extra_args[@]}"; do
echo " | ${xtra}"
done
fi
The example script supports various argument patterns:
./example-command.sh --dir /tmp --verbosity 2 --dry-run true
Output:
This is a no-op example command that just shows the arguments:
Directory: /tmp
Verbosity: 2
Dry run: true
Parallel: 4
When EXTRA_ARGS=true
, any arguments not matching a defined parameter are collected as positional arguments:
./example-command.sh --dir /tmp file1.txt file2.txt
Output:
This is a no-op example command that just shows the arguments:
Directory: /tmp
Verbosity: 1
Dry run: false
Parallel: 4
Extra args:
| file1.txt
| file2.txt
The --
delimiter is the standard Unix/Linux convention for marking the end of option processing. This is essential when you need to pass values that might otherwise be interpreted as options:
# Pass a filename that starts with a dash
./example-command.sh --verbosity 1 -- -my-filename.txt
# Pass a negative number as a positional argument
./process-data.sh --scale 2 -- -10.5
# Ensure all subsequent arguments are treated literally, not as options
./secure-script.sh --config settings.conf -- --potentially-dangerous-flag
Example output with the example script:
./example-command.sh --verbosity 1 -- --this-looks-like-an-option but-its-a-positional-arg
Output:
This is a no-op example command that just shows the arguments:
Directory: /workspace/src
Verbosity: 1
Dry run: false
Parallel: 4
Extra args:
| --this-looks-like-an-option
| but-its-a-positional-arg
Without the --
delimiter, the script would attempt to interpret --this-looks-like-an-option
as a named parameter, resulting in an error since it's not defined.
When running with verbosity level 2, the script shows the effective command line options, including default values:
./example-command.sh --verbosity 2 input.txt
Output:
Running with these effective options:
./example-command.sh --dir /workspace/src --verbosity 2 --dry-run false --parallel 4 -- input.txt
This is a no-op example command that just shows the arguments:
Directory: /workspace/src
Verbosity: 2
Dry run: false
Parallel: 4
Extra args:
| input.txt
ArguBASH allows users to set environment variables that match the argument names to override the defaults. For example:
# Set default verbosity to 2 for all ArguBASH scripts that use this argument
export verbosity=2
# Run script - it will use verbosity=2 without needing --verbosity 2
./your-script.sh
# Command line arguments override environment variables
./your-script.sh --verbosity 3 # Uses verbosity=3
This makes it easy to set common preferences without modifying scripts or always having to provide the same arguments.
ArguBASH performs basic validation on argument names and structure (ensuring they're valid bash variables and properly formatted), but it doesn't validate the values provided by users. For important arguments, you should implement your own validation logic after the argument parser section:
# After the ARGUMENT PARSER section:
# Validate that the directory exists
if [[ ! -d ${dir} ]]; then
_error "Directory '${dir}' does not exist"
exit 1
fi
# Validate that verbosity is within expected range
if ! [[ ${verbosity} =~ ^[0-2]$ ]]; then
_error "Verbosity must be between 0 and 2, got '${verbosity}'"
exit 1
fi
This pattern lets you enforce constraints on argument values that are specific to your script's requirements.
For more complex, real-world examples of ArguBASH in action, check out the Boxed project on GitHub:
boxed.sh
- A script that runs Docker containers with specific behaviors and argumentsbuild.sh
- A build script with extensive argument options
These examples demonstrate how ArguBASH can be used in production scripts with many arguments and complex validation requirements.
ArguBASH supports tab completion for both Bash and Zsh shells, making it easier to use your scripts interactively.
To enable tab completion for ArguBASH scripts in Bash:
-
Place the completion script in a convenient location:
# Create a directory for Bash completions if it doesn't exist mkdir -p ~/.bash_completion.d # Copy the completion script cp /path/to/ArguBASH-completion ~/.bash_completion.d/ # Make sure it's executable chmod +x ~/.bash_completion.d/ArguBASH-completion
-
Source the completion script in your
~/.bashrc
or~/.bash_profile
:For newer Bash versions (4.0+):
# Add to your ~/.bashrc or ~/.bash_profile source ~/.bash_completion.d/ArguBASH-completion
For older Bash versions (such as the default on macOS):
# Add to your ~/.bashrc or ~/.bash_profile with specific commands source ~/.bash_completion.d/ArguBASH-completion command1 command2 ...
-
Reload your Bash configuration or start a new shell session:
source ~/.bashrc # or source ~/.bash_profile
The ArguBASH-completion script will automatically detect ArguBASH-compatible scripts and provide tab completion for their arguments.
If you wish to install this for all users, a common location is the /etc/bash_completion.d
directory. Just copy the ArguBASH-completion
file to that directory. If that directory exists, that is the best place to put if for global access.
cp ArguBASH-completion /etc/bash_completion.d/
Once it is there, you just need to start a fresh login shell to test it:
bash -l
# now test argument tab completion with ./example-command.sh --v_TAB_ to see it working
For Zsh users, ArguBASH includes a dedicated completion script that follows Zsh conventions:
-
Place the
_ArguBASH-completion
script in a directory in your$fpath
(the leading underscore in the filename is intentional and follows Zsh conventions):# Create a directory for Zsh completions if it doesn't exist mkdir -p ~/.zsh/site-functions # Copy the completion script cp /path/to/_ArguBASH-completion ~/.zsh/site-functions/ # Make sure it's executable chmod +x ~/.zsh/site-functions/_ArguBASH-completion
-
Ensure the completion directory is in your
$fpath
. Add this to your~/.zshrc
:# Add the site-functions directory to fpath fpath=(~/.zsh/site-functions $fpath)
-
Rebuild the Zsh completion cache:
rm -f ~/.zcompdump compinit
Once installed, any script using ArguBASH argument parsing will automatically get tab completion for its defined arguments when using Zsh.
If you wish to install Zsh completion for all users on the system, you can place the completion script in one of the standard system-wide directories.
Choosing the right directory:
- On Linux: Use
/usr/share/zsh/site-functions/
(standard location for most distributions) - On macOS: Use
/usr/local/share/zsh/site-functions/
(preferred for user-installed software)
If both directories exist on your system (common on macOS):
- Choose
/usr/local/share/zsh/site-functions/
if you're installing manually or via a package manager like Homebrew - Choose
/usr/share/zsh/site-functions/
only if you're integrating with system packages
Installation commands:
# For Linux systems (standard location)
sudo cp _ArguBASH-completion /usr/share/zsh/site-functions/
sudo chmod +x /usr/share/zsh/site-functions/_ArguBASH-completion
# For macOS or Homebrew-based Linux systems (preferred for user software)
sudo cp _ArguBASH-completion /usr/local/share/zsh/site-functions/
sudo chmod +x /usr/local/share/zsh/site-functions/_ArguBASH-completion
After installing to a system directory, users will need to either start a new Zsh session or rebuild their completion cache:
# Rebuild Zsh completion cache
rm -f ~/.zcompdump
compinit
These system directories are already in the default $fpath
, so users won't need to modify their ~/.zshrc
files.
- Values cannot start with a dash
-
- Older Bash versions (pre-4.0) require explicit completion setup for each command
For those curious souls who enjoy peering under the hood, this section provides some technical details of how ArguBASH actually processes your arguments. While not essential for basic usage, understanding these internals can help you leverage ArguBASH more effectively or troubleshoot any issues that might arise. Feel free to dig in if you like getting your hands dirty, or skip if you're just looking to use ArguBASH in your own code.
When processing command line arguments:
- Internal variable names use underscores:
vm_sku
- Command line options use dashes:
--vm-sku
- This conversion happens automatically in the argument parser
The argument parser is embedded directly in your script, making it:
- Completely self-contained with no external dependencies
- Portable across different environments
- Easy to distribute without worrying about dependency management
- Consistent in behavior regardless of the environment
The parser:
- Sets all default values (unless already set in the environment)
- This lets users override defaults by setting environment variables (e.g.
export verbosity=2
)
- This lets users override defaults by setting environment variables (e.g.
- Processes command line arguments, overriding defaults and environment variables
- Provides help functionality with
-h
or--help
- Handles validation and error reporting
- Collects positional arguments if enabled
To help visualize how ArguBASH processes command-line arguments, here's a flowchart showing the inner workings of the argument parser:
flowchart TD
Start([<span style="font-size: 150%">Script Execution Starts</span>]) --> DefineArgs
DefineArgs{{The Declarative **ARGS_AND_DEFAULTS** is loaded and EXTRA_ARGS is set}} --> ParserStart
ParserStart[/Start of **ArguBASH** parser\] --> EnvVars
EnvVars[Check Environment Variables for Overrides while setting defaults from ARGS_AND_DEFAULTS] --> ParseArgs
ParseArgs[Process Command Line Argument] --> NextArg{Next Argument?}
NextArg -->|Yes| IsHelp{Is it --help or -h?}
IsHelp -->|Yes| ShowHelp
ShowHelp[/Show Help/] --> HelpExit
HelpExit([Exit])
IsHelp -->|No| IsDelimiter{Is it -- and EXTRA_ARGS=true?}
IsDelimiter -->|No| IsOption{Does it start with --?}
IsDelimiter -->|Yes| CollectRest
IsOption -->|Yes| MatchParam{Match defined parameter?}
IsOption -->|No| ExtraEnabled{Is EXTRA_ARGS enabled?}
MatchParam -->|Yes| SetValue
MatchParam -->|No| ShowError
ExtraEnabled -->|No| ShowError
ExtraEnabled -->|Yes| AddPositional
SetValue[Set Variable Value] --> NextArgLoop
ShowError[/Show Error/] --> ErrorExit
ErrorExit([Error Exit])
AddPositional[Add to extra_args Array] --> NextArgLoop
NextArgLoop[Continue to Next Argument] --> NextArg
CollectRest[Collect All Remaining Args as Positional] --> FinalSteps
NextArg -->|No| FinalSteps
FinalSteps[Unset Blank Values] --> Verbosity{Is Verbosity > 1}
Verbosity -->|No| EndOfParser
Verbosity -->|Yes| LogEffective
LogEffective[/Log Effective Command Line Options/] --> EndOfParser
EndOfParser[\End of **ArguBASH** parser/] --> ScriptLogic
ScriptLogic([<span style="font-size: 150%">Your Script Logic Begins</span>])
-
Initialize with Defaults and Environment Variables:
- Set default values from the
ARGS_AND_DEFAULTS
array - Check for and apply environment variable overrides during this process
- This creates the base state before processing command-line arguments
- Set default values from the
-
Parse Command Line Arguments: Process each argument in sequence:
- If it's
-h
or--help
, show help and exit - If it's
--
andEXTRA_ARGS=true
, collect all remaining arguments as positional arguments - If it starts with
--
, try to match it with a defined parameter- If matched, set the variable and continue
- If not matched, show error and exit
- If it doesn't start with
--
:- If
EXTRA_ARGS=true
, add it to theextra_args
array - Otherwise, show error and exit
- If
- If it's
-
Final Processing:
- Unset any blank values (for later conditional checks)
- Log effective command line options if verbosity is high enough
- Begin your script logic with validated arguments
This flow ensures that arguments are processed in a predictable order of precedence:
- Default values (lowest precedence)
- Environment variables (override defaults)
- Command line arguments (highest precedence)
The ArguBASH tab completion system is designed to automatically detect and provide completions for any script using the ArguBASH pattern. Both Bash and Zsh completion mechanisms follow similar principles but with different implementations.
The Bash completion system works as follows:
-
Script Detection: When you type a command and press Tab, the completion function:
- Checks if the command exists as a file
- Verifies it's a bash script
- Scans for the
ARGS_AND_DEFAULTS=(
pattern near the top of the file - If found, identifies it as an ArguBASH-compliant script
-
Argument Extraction: If the script is detected as ArguBASH-compatible:
- Parses the script to extract all argument names from the
ARGS_AND_DEFAULTS
array - Builds a list of valid
--argument
options using the same parsing logic as the ArguBASH parser - Matches the ArguBASH format by converting internal variable names to command-line options
- Parses the script to extract all argument names from the
-
Completion Generation: Based on what you've typed so far:
- If you're typing an option (starting with
-
), it offers matching options - If you've just entered an option and need a value, it lets Bash use standard completion
- If you're typing an option (starting with
-
Version-specific Handling:
- Newer Bash versions (4.0+): Uses dynamic command detection and argument extraction with the
-D
flag - Older Bash versions: Requires explicit registration of commands for completion
- Newer Bash versions (4.0+): Uses dynamic command detection and argument extraction with the
The Zsh completion system follows similar detection principles but provides enhanced functionality:
-
Script Detection: Similar to Bash, the completion function:
- Checks if the command exists using
command -v
- Verifies it's a bash script and scans for the
ARGS_AND_DEFAULTS=(
pattern - Uses the first 4096 bytes for performance while scanning
- Checks if the command exists using
-
Enhanced Argument Extraction: When a script is identified as ArguBASH-compatible:
- Extracts not just argument names but also their descriptions from comment lines
- Only uses the first line of help text for each argument (multi-line help text is not supported in the completion menu)
- Captures default values for each argument to display in the completion menu
- Matches the ArguBASH format by converting internal variable names to command-line options
- Builds a comprehensive set of argument specifications for zsh's
_arguments
function
-
Rich Completion Display:
- Uses zsh's advanced completion system to show help text and default values inline
- Formats each option with its description:
--option[Description (default: value)]
- Only displays the first line of multi-line help text in the completion menu
- Always adds
--help
and-h
options with appropriate descriptions - Detects if the script accepts positional arguments (
EXTRA_ARGS=true
) and enables file completion
-
Zsh-Specific Features:
- Uses the
-S
flag with_arguments
to properly handle the--
delimiter - Leverages zsh's menu-driven completion interface for better user experience
- Integrates with zsh's file completion for positional arguments
- Provides contextual information directly in the completion menu
- Uses the
Feature | Bash Completion | Zsh Completion |
---|---|---|
Detection method | Pattern scanning | Pattern scanning |
Argument format | Matches ArguBASH conversion | Matches ArguBASH conversion |
Help text display | No | Yes, shows inline |
Default values | No | Yes, shows inline |
Positional arguments | Basic handling | Enhanced with file completion |
Configuration | May need explicit setup for older versions | Works with zsh completion system |
The completion systems for both shells are designed to be:
- Zero-configuration: Works automatically for properly structured scripts
- Lightweight: Adds minimal overhead to the shell
- Discoverable: Helps users find available options
- Consistent: Provides predictable behavior across different scripts
See the LICENSE file for details.