9 ms·
I wrote an bash enumerator because I was sick of xargs
- wallach-game 3mo agobashumerate — 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 https://github.com/wallach-game/bashumerate
- figmert 3mo agoHave you seen parallel?
- ggm 3mo agofind -print0 | xargs -0 -I {} "the {} iterated command"
- koolba 3mo agoAnd for most of those commands add a dash dash so that nothing with a dash prefix turns into options.
- deleted 3mo ago[deleted]
- somat 3mo agoXargs is fine, but openbsd has a -J option and every time I read the man page to figure out how to use it I read the -I and -J options and my brain glazes over. https://man.openbsd.org/xargs https://man.openbsd.org/xargs Other brain glazing obsd wierdness is it's two argument cd command, a cryptid I am unable to wrap my head around. https://man.openbsd.org/ksh#cd~2 https://man.openbsd.org/ksh#cd~2
- 0xbadcafebee 3mo agoI highly recommend memorizing the POSIX version of every *NIX command and sticking to them. 60% of the time, they work every time. (https://pubs.opengroup.org/onlinepubs/9799919799/idx/utilities.html https://pubs.opengroup.org/onlinepubs/9799919799/idx/utiliti...)
- ggm 3mo agoBSD vs linux with a standards committee inbetween.
- fiddlerwoaroof 3mo agoIn a world with nix and where nearly every system has zsh, restricting yourself to the POSIX version of these tools is masochistic.
- JoshTriplett 3mo agoI highly recommend using whatever capabilities are convenient of any utility you're running, and not caring about what other systems do unless you're actually trying to write a portable shell script.
- fiddlerwoaroof 3mo agoThe two arg cd is pretty useful (and, zsh implements it too because cd is a shell feature): if you have parallel directory structure (e.g. the way rails does tests) you can switch from app/b/c/d to spec/b/c/f by doing `cd app spec`
- em-bee 3mo agowhy would you ever pipe find into xargs instead of calling -exec? find -exec the '{}' iterated command ';'
- gumby 3mo agoBecause xargs is faster. Exec will invoke the command once per matching file (which is sometimes what you want, of course)! While xargs will accumulate a bunch of file names, then when it as n names will invoke the command with those names, while continuing to accumulate names until n is reached or the pipe closes. The size of n depends on the system, but is usually at least a thousand.
- em-bee 3mo agothe example as given does not accumulate, so that is what i worked with. find -exec command '{}' '+' accumulates file arguments too. the only advantage of xargs is that you can tell it how many arguments to accumulate,̶ ̶t̶h̶e̶ ̶d̶o̶w̶n̶s̶i̶d̶e̶ ̶o̶f̶ ̶x̶a̶r̶g̶s̶ ̶i̶s̶ ̶t̶h̶a̶t̶ ̶y̶o̶u̶ ̶h̶a̶v̶e̶ ̶t̶o̶ ̶s̶p̶e̶c̶i̶f̶y̶ ̶t̶h̶e̶ ̶n̶u̶m̶b̶e̶r̶,̶ ̶w̶h̶e̶r̶e̶a̶s̶ ̶f̶i̶n̶d̶ ̶j̶u̶s̶t̶ ̶f̶i̶t̶s̶ ̶a̶s̶ ̶m̶a̶n̶y̶ ̶a̶s̶ ̶i̶t̶ ̶c̶a̶n̶.̶
- unsnap_biceps 3mo agoxargs will fit as many as it can in 128 KiB or the system limit, which is smaller, so in practice, it's almost always pretty similar default packing
- em-bee 3mo agoyou are right, i forgot to check the default. fixed my comment.
- xorcist 3mo agoThe problem with find is that you can't specify the maximum tolerated command line lengths, and find hasn't historically been very smart about it (it just had a compiled-in value). Apparently this is fixed in GNU find, but for older systems and other platforms that may still be an issue. Another feature missing in find that xargs has is the maximum processes to start at a time. find will run the commands in sequence, but in many situations you really want to run a bunch in parallel.
- caminanteblanco 3mo agoObligatory XKCD: https://xkcd.com/927/ https://xkcd.com/927/
- butvacuum 3mo agoalong with: I love standards- Theres soany to choose from!
- eqvinox 3mo agoNot 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
- fiddlerwoaroof 3mo agoI just use while’s default variable name, $REPLY most of the time. But `while` is my preferred tool for the xargs problem in most cases.
- JoshTriplett 3mo agoI use "| while read" as well, because it works well in a pipeline and handles embedded spaces. It doesn't handle embedded newlines, but in practice, real files have embedded spaces, while embedded newlines only happen in test cases and exploits. (You can do actual NUL-delimited reads with `-d ''`, but for a quick command-line operation that's generally not necessary, and if you're going to be that careful you probably also need `-r`.)
- laughing_man 3mo agoDepending on the actual command, this can be far slower and less efficient than xargs. You're creating a separate process for each invocation of bar when a lot of commands will take many targets for a single invocation. Try this with find and grep vs xargs. There's a big difference.
- eqvinox 3mo ago3 reasons against that: * in a lot of cases the performance just doesn't matter * xargs gets you the spaces in filenames landmine * some commands don't even support multiple target filename arguments For scripts in long term use, yeah, sure, figure out xargs maybe. Any other situation with a "| while read" solution, especially on an interactive session, is an oddball and simplicity wins.
- 3mo ago
- tester457 3mo agoOn 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.html https://www.gnu.org/software/parallel/parallel_alternatives.... [1] https://www.gnu.org/software/parallel/#Tutorial https://www.gnu.org/software/parallel/#Tutorial
- somat 3mo agoI have used echo as a sort of poor mans equivalent for a safe check of a pipeline, removing the echo when I felt the rest of the pipeline was working correctly. shell stuff | xargs -n 1 -I % echo real command and % args I have also been known to write scripts where instead of executing the critical parts it prints them. Then a dry run is script and the real run is script | sh
- bryancoxwell 3mo agoLove that idea, thanks for sharing
- krackers 3mo agoShouldn't you use echo instead of cat?
- somat 3mo agoyes echo, total brain fart there. corrected.
- quotemstr 3mo agoI love GNU Parallel too. I love how it's free software and how I can patch out the obnoxious citation notice.
- 3mo ago
- samtheprogram 3mo agoLiterally just use xargs with -I {} and quotation marks?
- laughing_man 3mo agoThat won't save you from weird file names, but null termination will.
- samtheprogram 3mo agoPassing "{}" handles most sane cases including spaces. If I'm doing bash that needs to be robust (rare and/or dotfiles) or know the folder/dataset has weird filenames, sure.
- raggi 3mo agoin 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" }
- PunchyHamster 3mo agomissed the point. reason to use xargs or parallel are generally two: list of arguments is too long, or list of arguments that is kept in memory would take too much for example for a in `find / ` ; do echo $a ; done will take A LOT of memory, while using find's -exec, xargs, or parallel will not
- foobarqux 3mo agoBut bashenumerate doesn't do that? The parent is saying you should zsh shortloops instead of bashenumerate not zsh shortloops instead of xargs.
- unsnap_biceps 3mo agoI looked into the source and the underlaying source uses a glob and suffers from the issue you brought up. https://github.com/wallach-game/bashumerate/blob/master/lib/enumerators/files.sh https://github.com/wallach-game/bashumerate/blob/master/lib/...
- raggi 3mo agoIn my experience once you get to the point where you run out of space in the glob you’re often suffering with poor performance from spawning children as well and it’s time to move to a more formal program even if it’s a script, writing out work plans and completions to list files to avoid wasted time. It’s often a great guardrail to remind you to do this
- 0xbadcafebee 3mo agoI 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.
- montag 3mo agoHm. Underrated comment
- deleted 3mo ago[deleted]
- loremm 3mo agoI 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
- porridgeraisin 2mo agoThis is the way. Works very well.
- PunchyHamster 3mo agoI feel like it could be just alias to some particular GNU Parallel set of options
- chasil 3mo agoI 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.
- ivlad 3mo agoWas exactly my thought: why not to use null termination? Looks like a case where reading man page would have spared writing another copycat utility.
- rmunn 3mo agoAnd null termination is guaranteed to work, because the only two characters forbidden in Unix filenames (for most varieties of Unix, I won't guarantee there aren't some weird variants out there) are / and null. The only times I've needed something more than `find -print0 | xargs -0` has been when I need to apply logic to decide whether to process one of the files, in a way that's not easy to express in a `find` command. Then I write a small script with a for loop and if statements inside it. But more people should know about `-print0`. It's the answer to 95% of the problems with `find | xargs`.
- Walf 3mo agoYeah, and I invariably add -r to xargs, so as not to execute the command unless results come through the pipeline. If one is working with whole lines of text, setting the delimiter to newline is often desirable: xargs -d \\n
- deleted 3mo ago[deleted]
- deleted 3mo ago[deleted]
- teo_zero 3mo agoGood 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.
- montag 3mo agoI thought -- was typically a separator for passing a list of arguments directly to some subcommand
- altairprime 3mo agoThe historical meaning is, "do not interpret command line arguments following --"; e.g. the classical form shown by `echo > -f; rm -- -f`. Git has a more complex interpretation of it and no doubt there's others, but this root interpretation remains generally sound: It acts as a boundary between 'complex and intelligent processing of @ARGV elements' and 'every remaining element of @ARGV after -- is treated a string literal without further processing'.
- dboreham 3mo ago55 comments and nobody mentioned the incorrect English in the title?
- fhn 3mo agoI'm glad you here to save us. What would we do without you?
- db48x 3mo ago> 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.
- AdieuToLogic 3mo agoTo support your recommendation and redress the strawman the article postulates, the post's author could have replaced: find . -name '*.log' | xargs rm With: find . -name '*.log' -print0 | xargs -0 rm
- tjalfi 2mo agoThis one doesn't need xargs. find . -name '*.log' -delete
- sgarland 2mo agoTHANK YOU. I kept nodding along to all of the xargs comments, thinking “sure, but what about the even easier solution?”
- adolph 2mo agoAs well as find has an -exec param to perform things one at a time or all with the same command by using a slash semicolon or a plus sign respectively: #order files from different levels in a file hierarchy by size: find . -type f -maxdepth 1 -exec ls -hlrS {} + #output metadata for each file sequentially find . -type f -maxdepth 1 -exec file {} \;
- jsrcout 3mo agoFor tools that don't support -0, you can add the NULs yourself without much fuss. It's a one-liner in awk/perl/sed. Very handy.
- 3mo ago
- gfalcao 3mo ago> 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... :)
- gfalcao 3mo agoAnother trick that took me years to learn is to use `xargs -I` to split the results into "items" For example `ps aux | grep process-name | grep -v grep | awk '{ print $2 }' | xargs -Ieach kill -9 each`
- ivlad 3mo agoOr, you use `xargs -0` for null termination instead of white space termination. `find` conveniently supports `-print0` that will use null character as separator.
- ykonstant 3mo agoTry not to do that in an uncontrolled file system. Filenames can and will have newlines, including trailing newlines, because evil people like myself inject them everywhere in our local user folders to keep sysadmins on their toes. Use the (now, finally, POSIX) -0/-print0 options for all file parsing which produces the correct behavior on all UNIX systems.
- AdieuToLogic 3mo ago> 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/ https://xkcd.com/927/
- G_o_D 3mo agoAtleast follow standard practice in your example Fails : enumerate -f '.txt' -- 'wc -l {}' For all use cases Correct : enumerate -f '.txt' -- 'wc -l -- {}'
- fhn 3mo agocalling it 'bashnumerate' and then have the command be 'enumerate' is confusing. find one and stick with it.
- ConanRus 3mo ago[dead]
- scrame 3mo agofind -print0...|xargs -0... works for me, and i don't always want to execute something and xargs can run parallel processes. i feel like this guy never bothered to read the man page.
- zxexz 3mo agoI don’t want to be a downer here, but the structure of this repo and the verbosity+language of the docs feel 80% vibecoded. Not that that’s wrong; I just feel kinda gullible for even clicking on this. One uses xargs or parallel only a few times before they remember some of the quirks that but them. And then they become cautious. And then it’s muscle memory. And if it’s not an often occurrence, they learn to check the man page. Anyways, in a world of “vibecoding” why add another “tool” to the mix when the LLMs have been trained on all our stackoverflow-posted grievances to begin with?
- dundarious 3mo agoIf you want a shell to interact with the results, you can of course just use a (sub)shell. ls -1 ./*.sh | xargs -rd\\n sh -c 'for i in "$@" ; do ... ; done' sh 1. not strictly necessary to use -1 as I believe all common ls detect !isatty(stdout) and produce line-by-line output anyway. 2. xargs -r just doesn't run the command if there's no input, also not strictly necessary but I'm addicted to using it because it's the sensible default to me. 3. xargs -d\\n makes it collect fields as full lines, which is what you typically want, unless you're able to generate NULs. 4. use whatever shell you want of course, but I don't use bashisms, etc., by default, /bin/sh is fine for me, even if it's dash. 5. the trailing "sh" at the end is due to a quirk of `sh -c` usage, where $0 is the first non option argument, so `printf %s\\n 1 2 3 | xargs -rd\\n sh -c 'for i in "$@" ; do printf "%s " "$i" ; done ; echo'` (note the lack of trailing "sh") would only print "2 3 " as $0 is not included in "$@" ($0 is 1, $1 is 2, $2 is 3). It's very easy to just always give the shell name itself manually as $0 instead of trying to ingest "$0" into your logic. Of course, you could `find . -maxdepth 1 -type f -name '*.sh' -print0 | xargs -r0 ...` instead, depending on what you're up to, that may be the easiest. It's definitely the simplest -- as long as your xargs has -0 support.
- dspillett 3mo ago> not strictly necessary to use -1 as I believe all common ls detect !isatty(stdout) I remember, though from the dim an distant past so it could be a long-fixed bug, this not working in at least one circumstance. I've explicitly included -1 in scripted calls to ls since. Of course we are breaking the best practice rule of not trying to parse the output of ls, so problems are not unexpected… As a generally thing I like to include directives like this in scripted calls even if they happen by default anyway, because is makes my intent clear: I expect the output to being in simple single-column format and the rest will break if it isn't. I even sometimes go as far as specifying --sort=name if nothing else in the pipeline is going to enforce that. > as long as your xargs has -0 support I don't think I've encountered an xargs that doesn't have this support for a long time, though I don't work with embedded stuff so maybe there are cut-down versions out there still in active use for space reasons. The problem I've hit numerous times is wanting to do something between “find -print0” and “xargs -0” and that something not supporting NUL as the item delimiter.
- IdiotSavage 3mo agoIn this thread: bash experts with arcane knowledge, unintentionally demonstrating how awful bash is. The obvious solution would be to use something more sane, like PowerShell or nushell, but instead old experts will always defend the skills they have honed for years, while criticizing anything that's different.
- lobofta 3mo agoSwitched to Nushell and I am not looking back. I don't see any major reason why we should keep dragging Bash into the twenty first century. Nushell is the first time I feel like I can write complex systems operations in a shell without having to spend either a ton of time in the docs or being at the mercy of an LLM. It is godsend.
- piaste 3mo agoI tried to switch to nushell full-time but couldn't stick with it. Ironically, the main friction point were not old-fashioned tools (which `from ssv` usually handled nicely) but the 'new generation' of core CLI tools like eza or fzf. They have really nice visualizations, but they do not output structured data as a middle step, so all the colours and lines only play havoc with nu's parsing. Since I need to "ls" a lot more often than I need to do data manipulation, the tools won and I went back to zsh. Still keep nu around for the occasional config/data file wrangling though.
- kfsone 3mo agoI was the kind of shell guru whose teeth itched when they saw someone doing `grep | awk`. Then I had to try and bring Windows into a Mac+Linux CI system under Jenkins groovy files that were full of `"""sh` fragments, shell scriptlets wrapping python, etc, etc, and I don't bat (I don't groovy either). Option 1: Learn to bat and try to translate. Hmm. No. Just no Option 2: ? Pwsh core had just come out. My immediate thought was that it would be great material for an anti-MS-ragging blog post, but then a line leapt out at me from one article I was glossing over: "... POSIX Terminal Shell Spec ...". I still wanted that anti-MS-ragging blog material, so I decided to try and use Pwsh as a Rosetta stone until I got to a point I could convert to a real language. But things just began to click for me. It was like going from Perl to Python - suddenly everything is an object and you can interact with everything* that way. There's no need for grep or awk or sed in pwsh, because the output of a shell command is an object -- a string (or []byte). It has methods. (netstat -an).replace("192.168.86.", "10.0.100.") 6 years later, pwsh is the default shell on my Mac, Ubuntu boxes, lab vms, ... everything but my docker containers unless I'm feeling feisty.
- pjmlp 3mo agoOne thing with classical UNIX commands, is that you can expect to find them into random computers besides one's own laptop. Not everyone has the luxury to only work with their own computer, or run random software on IT/customer managed systems.
- ykonstant 3mo agoThis is why I tend to stick to POSIX shell scripting these days, avoiding even bash. The restriction does make some things too painful, though. Before the latest POSIX revision, certain workflows were comically hard to do (unless you combine sh with... M4). The 2024 revision injects some much-needed sanity, but I am wondering, will random computers have shells compliant with that revision?
- pjmlp 3mo agoBack in the day, as I mentioned around a few times, I found refuge in XEmacs, coming from the comfy Borland IDEs world. However, I also had to get comfortable enough with vi, because most customer systems that we would be required to access on a support visit, or remotely, only had ed and vi available. Even if we nowadays stick with Linux distros instead of UNIX in general, there is still the issue of what is there by default. Yep POSIX shell scripting can be a bit painful, which is why knowing a bit awk, perl and sed might help as well, as they tend to be available by default.
- kfsone 3mo agoCareful - you start from the POSIX terminal spec, you think maybe it would be interesting having objects instead of raw text streams, and next thing you've reinvented powershell... (*35 years living and loving sh/ksh/bash/dash etc, only tried pwsh so I could write some comparisons and slag off MS a bit; now it's my default shell on everything)
- account42 3mo ago> Consistent syntax — same {} placeholder for files, lines, ranges, or lists Inconsistent syntax native bash methods so its an additional syntax to learn. > Template mode — single-quoted commands work as shell templates: enumerate -f '*' -- 'cat {} | head -5' Passing commands a a single string is BAD. Now you have to think about escaping and quoting. What does {} get replaced with if the enumerant contains unsafe characters? Can it be used as part of a larger argument or only on its own? Who knows, it's not bash. Compared to a bash loop its also always a subshell with all the implications that has - even find can be piped into a normal bash loop. > Filters — --include and --exclude with glob patterns A fraction of what find or native loops provide. And since this can't replace them in general enumerate is an additional thing to learn on top. > Extensible — drop a file in lib/enumerators/ to add custom sources To extend bash loops you don't even need root access, you just add the code to the loop.
- iririririr 3mo agobeing consistent in a sea of inconsistency is a good thing, no matter how hard you try to paint otherwise. the solution have to start at some point. But the rest, yeah, scary.
- vladde 3mo agoi often find xargs ends up biting me, and i have wanted some alternative for a while... but i don't think this is the one for me. it feel like the syntax here is odd. it still requires me to write quote my command i want to run? unfortunately i'll have to pass on this. personally i'd want some variant where i can still auto-complete commands and have just have {} as a placeholder. (maybe time to learn how to use xargs for real?)
- jllyhill 3mo agoDid you write it or did Claude code slopcoded it for you? Claude is the contributor to all your other repositories. There is a world of difference between "here's a problem that I'm really concerned with and poured all my expertise to solve it" and "I told Claude to fix it for me and now I'm gonna abandon it as soon as I'm done with the HN advertising".
- cryo32 3mo agohttps://imgur.com/a/K9TPYgf https://imgur.com/a/K9TPYgf
- kleiba2 3mo ago> There is a world of difference between "here's a problem that I'm really concerned with and poured all my expertise to solve it" and "I told Claude to fix it for me and now I'm gonna abandon it as soon as I'm done with the HN advertising" https://en.wikipedia.org/wiki/False_dilemma https://en.wikipedia.org/wiki/False_dilemma
- giov4 3mo agoI lol'd, but do you think this is valid? https://github.com/wallach-game/bashumerate/pull/1/files https://github.com/wallach-game/bashumerate/pull/1/files to me looks like a right solution, even if I was also tired of writing for loops by hand usually
- giov4 3mo agoOn a second thought I think that the effort in trying to find a shell uncomfortability problem and trying to solve it with a "wrapped workaround" still represents positive effort and should be supported and fostered without jumping directly in 90's like rtfm mode. especially in the case of a younger profile, learning and putting dev effort, even if vibed or redundant, its still effort and a learning activity! https://github.com/wallach-game https://github.com/wallach-game so I support this even if the result and problem solving can be less significant
- Dibby053 3mo agoIt's possible the tool is useless and a consequence of not reading the manual, but it could just be the tool is nice but the examples are too simplistic. In any case, toxicity aside, publishing a command line project and having someone dismiss the examples with shell oneliners is also a valuable lesson, and I don't think it will make him a worse developer.
- giov4 2mo agothat's what I also thought when I saw the pull request, that it could be a useful lecture. But again the usefulness of the final tool should not compromise appreciation of effort and learning. Unless the tool targets, claims or pretends to be the best, final and universal solution to such problem. I believe it isn't, I will still fall back to my bash memories, I will not need, install and use this tool, I will not need, install or use custom shells. The effort wasted in re-aligning my brain to a tool change would superseed instantly the few second effort needed to reach the needed bash one-liner. Also, didn't you also feel good and amazed when completing a very long and nested working one-liner? wasn't that orgasmic? :D
- tom_ 3mo agoI never liked xargs either. My replacement is kind of like "xargs -n 1 -d '\n' -J '{}'", which experience has taught me is almost always what I want. It consumes all of its input before starting, so it knows how many files it has to process, and it can print progress to stderr and/or the terminal title as it goes. It can run each command via the shell if you want. It has --dry-run and --keep-going. It can read the file names from a file rather than stdin. I have a few more ideas for things it could do, but I haven't needed to add them yet. (For enumerating files, I use find or dir/b/s, possibly combined with grep, then pipe the result in.) People moaning about avoiding non-basic use of xargs and bash (and inadvertently demonstrating in many cases why some of us think that xargs sucks) miss a large part of the point, which is that it's nice to have a tool that does exactly what you want, and works in a way that's convenient for you, and isn't so widely used that you have to worry about modifying it. If you find the tool doesn't work the way you like, you can just change it. You don't have to be answerable to anybody else. I think tptacek's quite good essay could be relevant: https://sockpuppet.org/blog/2026/05/12/emacsification/ https://sockpuppet.org/blog/2026/05/12/emacsification/ (You don't have to use LLMs for this! I wrote my program by hand, it's only like 250 lines of Python, and you could write one too. But, whichever barriers to entry prevent you from creating your own tools for yourself, using an LLM would probably lower at least some of them.)
- zombot 3mo ago> and pray your filenames don’t have spaces `find` has `-print0` and `xargs` has the matching `-0` flag for this. So this specific argument makes me doubt the author knows their tools. Stopped reading at this point.
- kekqqq 2mo agoParallel and sed are already well-established tools.
- mslusarz 2mo agoI was also sick of bash ways of dealing with lots of data, spaces in file names, etc, so I created csv-nix-tools: https://github.com/mslusarz/csv-nix-tools https://github.com/mslusarz/csv-nix-tools E.g. removing all temporary files without the need to deal with spaces, glob limits, or silly find syntax: csv-ls -R -c full_path . | csv-grep -c full_path -e '~$' | csv-exec -- rm -f %full_path
- tom_alexander 2mo ago> Or maybe you pipe into xargs and pray your filenames don’t have spaces: > find . -name '*.log' | xargs rm No need for prayer: find . -name '*.log' -print0 | xargs --null rm That uses null as a delimiter instead of linebreaks.
- ninkendo 2mo agoRelated: I wish there were a portable way for xargs to treat newlines as delimeters but not other spaces. Since 99.9% of the time that's what you want. (GNU's has this with -d/--delimiter, but BSD's, and thus macOS's, doesn't.) --null/-0 is portable and helps, but it means the input has to be NUL-delimited, which is... rare. Sure, find has -print0 but (a) I wish I didn't need to do that, and (b) sometimes it's nice to just pipe `ls` output into xargs, without a `... | while read i; do echo -ne "${i}\0"; done | ...` kludge in the pipeline. Because spaces in filenames is just common enough to be something that will bite you eventually, but newlines in filenames are a straight evil that you can basically always say is the filename's fault.
- danlitt 2mo agoI think this post finally convinced me shells are awful and should be avoided.
- inigyou 2mo agoThere's room for so much more innovation in the shell space. Microsoft did it with PowerShell - Linux seems to be stuck in the 1980s. You do have newer shells like fish, but they seem to only mess with the on-screen layout of the command prompt (while being stupid enough to still run within a terminal) and not the commands themselves. I wonder if the generation one or two before mine grew up without shells and then had to make them and had no particular preconceptions, but my generation grew up treating the way shells work as a law of physics and thus doesn't innovate. Actually I wonder how much ossification is explained by this in general.
- hsbauauvhabzb 2mo agoShells imo are legacy on legacy, I like bash and zsh, they’re nonsensical but they work. Powershell is undoubtedly saner, but I hate it. I think the whole concept could be rewritten from the ground up to be modern, but reaching critical mass and mvp is too damn difficult, and the majority of mac/Linux users probably don’t want it.
- anthk 2mo agoIt's the opposite. Plan9's rc(1) it's much saner than Bash, Ksh and PowerShell.
- inigyou 2mo agoIf you build it and it's better, they will come. None of us here are building it.
- hsbauauvhabzb 2mo agoThere are already alternative shells. I think there’s some stuff fairly deeply rooted into gnu that’s an ‘issue’ for rebuilding and turns an effort into a complete redesign, making the whole thing hard to achieve.
- MrBuddyCasino 2mo ago
- guido26 2mo agoMy Summary of comments: Multiple commands in use can interpret a series of string values in weird ways. You need to establish that every program's interpretation points to the same object before processing the object through the command chain. Stopping a bad command is more important than running the good ones. There is no tool that does this one job.
- pif 2mo ago> Or maybe you pipe into xargs and pray your filenames don’t have spaces So they wrote a new tool and posted it on HN before checking the manual about null character termination... Not trustable at all, what a waste of time!
- theideaofcoffee 2mo agoSame thought I had, and that is where I stopped reading. All of these looping/enumerating techniques, including the weirdness with null-terminating strings to get around the shell's inherent treatment of spacing, are muscle memory for anyone that has spent more than 27 minutes in the shell at any point in the last 30 years. Yes it's weird because it's old. Deal with it. Why make yet another tool with yet another set of quirks?
- eviks 2mo ago> Why make yet another tool with yet another set of quirks? Obviously because not all sets are equal?
- jeffffff 2mo agoy'all still write shell commands manually?
- dtj1123 2mo agoDon't forget gnu parallel
- martinflack 2mo ago> enumerate -r 1 10 -- 'printf "%02d\n" {}' The printf zero-padding should be a built-in feature, as dealing with lots of filename structures and date structures needs zero-padding. I often end up doing things like "for i in $(seq -w 1 100); do.." in bash. My preference would actually be that -r does automatic zero-padding to fit the widest number that will come out of the range, and another variant like -R would suppress that behavior; but it could also be an optional switch. It might also be nice to have the code recognize when start is greater than end, like -r 10 1, and support backwards-counting.
- Borborygymus 2mo ago> Or maybe you pipe into xargs and pray your filenames don’t have spaces Or maybe use: `find ... -print0 | xargs -0 ...` I guess you're still hoping your filenames don't contain an ASCII NUL, although that's a fairly reasonable assumption for all but the most paranoid use-cases.
- simon04 2mo agoHere is a 136 line Python version: https://github.com/simon04/dotfiles/blob/master/.local/bin/enumerate.py https://github.com/simon04/dotfiles/blob/master/.local/bin/e...