I wrote an bash enumerator because I was sick of xargs

wallach-game 103 points 76 comments July 20, 2026
numerlab.org · View on Hacker News

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.

Semantic search powered by Rivestack pgvector
14,369 stories · 134,336 chunks indexed