I wrote an bash enumerator because I was sick of xargs
wallach-game
103 points
76 comments
July 20, 2026
Related Discussions
Found 5 related stories in 941.3ms across 14,369 title embeddings via pgvector HNSW
- A 13th-Century Enumeration Algorithm, Ignored for 700 Years viebel · 16 pts · July 07, 2026 · 47% similar
- I made a terminal pager speckx · 112 pts · April 15, 2026 · 44% similar
- Show HN: Bash4LLM+ – A lightweight, dependency-free Bash wrapper for LLM APIs kamaludu · 43 pts · June 28, 2026 · 43% similar
- Safe ways to do things in bash (2023) gautamsomani · 19 pts · March 31, 2026 · 42% similar
- Show HN: Pu.sh – a full coding-agent harness in 400 lines of shell nahimn · 74 pts · April 30, 2026 · 41% similar
Discussion Highlights (18 comments)
wallach-game
bashumerate — iterate over files, lines, ranges, or lists with a consistent {} syntax. No for loops, no find -exec, no xargs flags to remember. enumerate -f '*.sh' -- wc -l {} enumerate -L a b c -- 'echo {}' Under 150 lines of bash, pluable sources, NUL-safe. https://github.com/wallach-game/bashumerate
ggm
find -print0 | xargs -0 -I {} "the {} iterated command"
caminanteblanco
Obligatory XKCD: https://xkcd.com/927/
eqvinox
Not sure I see the point of this. Remembering a bunch of options on one tool is no better than a bunch of tools/constructs? Especially if the latter are useful elsewhere. And it can't be used for scripts unless you start shipping it alongside, which… nah. Just go with foo | while read X; do bar "$X"; done
tester457
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. Parallel has an option for almost everything, it's almost too much. But I have shopped around for alternatives. The creator Ole Tange maintains a painstakingly long article of the alternatives and their differences. [0] The gnu parallel book and reading materials [1] are excellent too. [0] https://www.gnu.org/software/parallel/parallel_alternatives.... [1] https://www.gnu.org/software/parallel/#Tutorial
raggi
in zsh you can just write: for x (*.sh); echo "before $x after" or for x in *.sh; echo "before $x after" or for x (*.sh) { echo -n "before "; echo -n $x; echo " after" }
samtheprogram
Literally just use xargs with -I {} and quotation marks?
0xbadcafebee
I wanted something simpler — one consistent way to iterate over anything. That's not actually simpler though. Simple is removing everything unnecessary. You took commands which could already do what you wanted, and added an extra program which calls them in specific ways. This will add bugs and maintenance headaches, not be portable, etc. This is added complexity. The reason you made this script is not because you wanted simpler , you wanted easier . There's nothing wrong with that, and I'll grant you it probably is, especially for those unaccustomed to these commands. But easier != simpler. Often you'll find that simple is hard and easy is complexity deferred.
loremm
I have found that the most reliable way I like is to just construct the command externally and then pass to gnu parallel (mostly for --eta and --tmuxpane). And the great thing is, as others say, xargs -I. I prefer for shortness (and few collisoins), '@' seq 1 10|xargs -I@ echo 'bash run.py @'|parallel -j 10 I know the echo is a little silly but then I can remove the |parallel and see if it's right. And if I don't want parallelism, I just pass to bash
PunchyHamster
I feel like it could be just alias to some particular GNU Parallel set of options
chasil
I use: find . -name '*.log' -print0 | xargs -0 rm For this simple example (derived from the article), find also has a delete operator. This null termination is now a POSIX standard.
teo_zero
Good idea but strange syntax. It would be more idiomatic if the command came first and the list of globs last. Additionally the use of "--" is not what everybody expects: here it is used to introduce one argument, the command, while it's usually meant to introduce multiple arguments without worrying if they have a leading "-". A possible revised syntax with command as the first argument followed by a list of globs optionally introduced by "--" would allow to enumerate all files with a leading "-", which the current syntax cannot: enumerate 'whatever {}' -- '-*' I'm assuming "-f" for simplicity, but the same reasoning holds for "-L" too.
dboreham
55 comments and nobody mentioned the incorrect English in the title?
db48x
> Or maybe you pipe into xargs and pray your filenames don’t have spaces… Always use -0. Most gnu utilities support it. It makes them put a null byte after every filename instead of a newline. Completely eliminates the problem of dealing with whitespace in the filenames.
gfalcao
> Or maybe you pipe into xargs and pray your filenames don’t have spaces… Most of this, if not all, is fixable by adding a `export IFS=$'\n'` to your bashrc. I'm not trying to disregard your project, just point out something that took me years to learn and I currently use extensively to solve this very problem. Perhaps you didn't know about it until now... :)
AdieuToLogic
> Ever found yourself writing this? for f in *.txt; do wc -l "$f" done No, because `wc` accepts multiple files. And the example given is incorrect for any file having a `.txt` suffix and whitespaces. > Or this? find . -name '*.sh' -exec wc -l {} + No. > These all work, but each has its own syntax, its own flags, its own quirks. I wanted something simpler — one consistent way to iterate over anything. And therein lies the proverbial xkcd standards[0] proof. 0 - https://xkcd.com/927/
G_o_D
Atleast follow standard practice in your example Fails : enumerate -f ' .txt' -- 'wc -l {}' For all use cases Correct : enumerate -f ' .txt' -- 'wc -l -- {}'
fhn
calling it 'bashnumerate' and then have the command be 'enumerate' is confusing. find one and stick with it.