UPDATE: NEW FINAL ANSWER:
Note that sort -zu
sorts and removes duplicates on a null-separated (-z
) list.
rg 'my pattern to match' -0 -g '*.txt' -l \
| sort -zu \
| xargs -0 -I{} -- dirname {} \
| xargs -0 -I{} -- tree {}
OLDER ANSWER DETAILS:
See the comments below this answer. My answer here isn't as robust as the other answer by @Stéphane Chazelas.
My answer below originally wouldn't properly handle any filenames with spaces or other whitespace in them, nor would it handle filenames which begin with dash (-
). Here is my response comment below:
@StéphaneChazelas, all of your comments make sense. Your answer is more robust. Using --null
(-0
) with rg
and with xargs
would for sure be more robust. Using --
would too. I guess I wasn't too concerned about those things because I'm running this command in a git repo where not one file has spaces in it nor begins with dash (-
). As for the multiple dirname
& tree
calls instead of one call with multiple paths, I was aware of that, but was okay with that too in part because I wanted an answer I could easily expand and add more pipes and commands to w/out drastically changing it.
So, look at both answers. His is technically better, but for my purposes, mine is "good enough" for now and points out that my original example in the question could have worked with super minimal changes. Ex:
# I should have done this (add `-0` to `rg` and add `--` to `xargs`):
rg 'my pattern to match' -0 -g '*.txt' -l | xargs -0 -I {} -- dirname {}
instead of this:
rg 'my pattern to match' -g '*.txt' -l | xargs -0 -I {} dirname {}
The answer by @Stéphane Chazelas and the comments under my question (including one by the maker of ripgrep himself!) are all useful and helped me figure out the following, which I think is the simplest and best answer because it's the simplest:
The output path strings from rg
are NOT null-terminated strings, so remove -0
from the xargs
command (or, conversely, add it to the rg
command as well). That's it! This now works:
# THESE WORK to get the dirnames!
# (`--null`/`-0` are removed from both `rg` and `xargs`)
rg 'my pattern to match' -g '*.txt' -l | xargs -I {} dirname {}
OR (same thing--remove the space after -I
is all):
rg 'my pattern to match' -g '*.txt' -l | xargs -I{} dirname {}
OR, you can force the path strings to be null-terminated by adding -0
or --null
to the rg
command, so this works too:
# ALSO WORKS
# (`--null`/`-0` are ADDED to both `rg` and `xargs`; note that for
# both `rg` and `xargs`, `--null` is the long form of `-0`)
rg 'my pattern to match' -g '*.txt' -l --null | xargs --null -I{} dirname {}
Now, by extension, we can pass all the paths to tree
as well like this:
FINAL ANSWER:
rg 'my pattern to match' -0 -g '*.txt' -l \
| xargs -0 -I{} -- dirname {} \
| xargs -0 -I{} -- tree {}
That's it! I simply needed to either add or subtract -0
or --null
from both rg
and all xargs
calls, to keep them all consistent and expecting the same delineators when parsing the multiple paths.
Adding -0
or --null
, however, is better, because then it allows paths with spaces or other whitespace in them, and adding --
as well is good because then it allows paths which begin with dash (-
). So, that's what I've done above.
Again though, see the other answer too. It also sorts, removes duplicates, and handles other intricacies.
See also
- More of my
xargs
learning and examples:
- How to recursively run
dos2unix
(or any other command) on your desired directory or path using multiple processes
- See
xargs
examples in my README, here: https://github.com/ElectricRCAircraftGuy/FatFs/tree/main
Keywords: how to use xargs properly; parse grep or ripgrep rg output paths with xargs
grep
has a-Z
/--null
option that should work fine with thatxargs
command. – muru Dec 03 '21 at 06:32--null
flag. – BurntSushi5 Dec 03 '21 at 11:37