bashumerate: A programmable iterator for your shell
bashumerate: A programmable iterator for your shell
Overview
bashumerate provides a unified way to iterate over different sources using a single {} placeholder, avoiding the need to remember multiple loop or xargs syntaxes.
How to use
Basic usage follows the pattern enumerate <source-flag> <source> -- 'command {}'. The four built‑in source types are:
-ffor files (e.g.,enumerate -f '*.sh' -- 'wc -l {}')-lfor lines from a file (e.g.,enumerate -l /etc/hosts -- 'echo {}')-rfor numeric ranges (e.g.,enumerate -r 1 10 -- 'printf "n=%d\n" {}')-Lfor explicit lists (e.g.,enumerate -L a b c -- 'echo item: {}') If the command is omitted, items are printed to stdout and can be piped elsewhere.
Features
bashumerate offers:
- Consistent syntax: the same {} placeholder works for files, lines, ranges, and lists.
- Template mode: single‑quoted commands act as shell templates, allowing pipelines like
enumerate -f '*' -- 'cat {} | head -5'. - Filters:
--includeand--excludeaccept glob patterns to limit the source. - NUL‑safety: the
-0flag produces NUL‑delimited output for safe handling of spaces and special characters. - Extensibility: custom sources can be added by placing a file in
lib/enumerators/without any registration step.
Adding custom sources
To add a new source, create an executable file named enumerate_source_<name> inside lib/enumerators/. The function must output NUL‑terminated items. For example, a Docker source:
enumerate_source_docker() {
docker ps --format '' | while read -r name; do
printf '%s\0' "$name"
done
}
After saving the file, the source is available as enumerate docker -- 'docker restart {}'.
Internals
The core implementation is about 140 lines of Bash. Internally, sources emit NUL‑delimited data, making the tool safe for filenames containing spaces or newlines. The {} placeholder is replaced at the shell level—no sed or eval tricks are used.
Installation
You can install bashumerate via Basher:
basher install wallach-game/bashumerate
Or manually clone the repository and symlink the binary:
git clone https://github.com/wallach-game/bashumerate.git
ln -s "$PWD/bashumerate/bin/enumerate" ~/.local/bin/
Naming
The name “bashumerate” is a concatenation of “bash” and “enumerate”, chosen because it directly describes what the tool does.
Community feedback
Comments on the Hacker News post show a mix of reactions:
- Some users appreciate the idea:
"I lol’d, but do you think this is valid? ... to me looks like a right solution, even if I was also tired of writing for loops by hand usually" — @giov4
- Others question the necessity and point out existing alternatives:
"I don’t want to be a downer here, but the structure of this repo and the verbosity+language of the docs feel 80% vibecoded." — @zxexz
- Critics argue that the tool adds another syntax to learn:
"Consistent syntax — same {} placeholder for files, lines, ranges, or lists. Inconsistent syntax native bash methods so its an additional syntax to learn." — @account42
- Some note that null‑terminated approaches already exist in standard tools:
"Or maybe you pipe into xargs and pray your filenames don’t have spaces … No need for prayer: find . -name '*.log' -print0 | xargs --null rm" — @tom_alexander
- A few mention preferring established tools like GNU Parallel:
"On the topic of xargs replacements, I love gnu parallel. The --dry-run flag of parallel made me confident to do more batch processing than I ever did with xargs." — @tester457
- There are also remarks about the broader shell ecosystem:
"In this thread: bash experts with arcane knowledge, unintentionally demonstrating how awful bash is." — @IdiotSavage Overall, the discussion reflects enthusiasm for reducing boilerplate as well as skepticism about adding yet another utility when established patterns already exist.