-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for replace in files #74
Comments
I don't think I'd be willing to do this. It would change rg from a tool that will never modify your files to one that will modify your files. It is also a very complicated feature to get right to make sure you don't really mess up files on disk. Just use |
Real search and replace would be an absolutely excellent feature. But I can well believe it would be painful and complex to implement. Perhaps there could be a reasonable middle way: if Something like: rg '(foo) (bar)' --replace '$2 $1' --diff-output > rg.diff
cat rg.diff
...
patch < rg.diff That has the advantage that the user couldn't easily mess up a directory by happening to add an argument and the business of modifying files is left to another command. |
@samuelcolvin Why would someone do that over using I guess your suggestion does satisfy one of my primary concerns, but it doesn't seem like good UX to me. |
Because for me (and lots of other developers) Most people seem to open up sublime or atom or their IDE when they want to do a search and replace. For me that says a lot about the dearth of decent tools in the terminal for this. I agree the UX isn't great but since some kind of review step is likely to be required anyway, it couldn't be that much more succinct. If you know what you want you could of course pipe the output of (by the way, I'm a big fan of |
@samuelcolvin Thanks for explaining. I can appreciate that With all that said, I am actively working towards moving more of |
Sorry if this is a stupid question, but what's the use case for |
Why is the output of |
nvm, it looks good, now that i actually tried it. sorry for the noise :) |
How about an option to print out the whole file? Than I can simply pipe it over the file if I wish to. That would make this easier: This can also work for multiple files: for f in (rg -l '(57ed11b0add205adee02a9bd)')
rg -C 9999999 -N '(57ed11b0add205adee02a9bd)' --replace '\'$1\'' $f | sponge $f
end (that's fish, not bash, but differences should be subtle) by the way this was easier to come up with than googling and reading |
I like @samuelcolvin suggestion on producing diffs, looks like a good compromise. The problem using
In any case, knowing that |
Let me say this: IMO, the cumbersomeness of
I, as the maintainer of this project, do not want to go down this road. I admit that the patch idea is a clever compromise, but I find the the UX to be very bad personally. It also doesn't stop the floodgates from opening to start supporting every nook and cranny of I suggest we drop this and wait for the components of |
I agree with your point, making a Better to wait for |
I second the statement that, given this, I found this thread trying to find out how to 'accept' the changes, after realising it output what I thought was a confirmation. I'm sure it's possible to pipe line numbers and changes to some other utility to apply the replacement, but I agree that it's non-obvious, and it would be good to be able to say in |
A lot of it is already done, but there is no canonical "libripgrep." I wrote up more details in #162. I've updated the documentation of |
@BurntSushi Would you be open to PRs implementing this functionality? |
@ticki Not really. I don't think any of my objections to this feature were related to my personal unwillingness to implement it initially. I am making good progress on #162. I'd rather see this functionality built out in a separate tool. My hope is that #162 makes this actually feasible to do without becoming an expert in text search. |
I made a little bash script for using ripgrep as a command-line find-and-replace tool. It might be terrible. But it works great for my use cases so far. (Note: You need to replace The idea is to first search and see what matches:
Then, press the Up arrow and edit in a replacement:
If it looks good, press the Up arrow again and add a
Voila! The changes should be written to disk. (I'm not saying that ripgrep should add a feature for "writing the replacements" – I'm just sharing that a couple of lines of bash can be enough :) ) (Edit: macOS support thanks to the next comment.) (Edit: Warning – there seems to be some bug that corrupts your file if |
For those on MacOSX who try out lydell's bash script solution, which does not support "head -n -1" (get all except the last line); you can replace "head -n -1" with " sed '$d' " (take the input and delete the last line). Thank you BurntSushi for ripgrep, and lydell for the simple solution. |
This is more easily accomplished using (GNU sed)
(BSD sed) <-- this includes OSx
(keep in mind here that I'll break down what is happening here:
This method works very well for me, fits in the UNIX philosophy, and avoids using any sort of extra shell script. For people googling "ripgrep search and replace", hopefully this will help you use some basic |
@z2oh Thanks for that write up! I would be delighted if you'd be willing to contribute that to the FAQ. :-) |
If you don't like
I'm guessing that the difficulty of handling cases like that in a robust manner is one of the reasons doing this in |
With
My script:
Not trying to promote my script or say that one is better than the other. But something to keep in mind :) Edited
The reason I say “try to spot if your replacements look good” is because |
@lydell I do like your solution, but it's a little disingenuous to say:
the equivalent |
No. Feel free to go build one or use any of the numerous projects linked above or in the FAQ. |
I started it, for my own use, before I mention at the top of the TL;DR that if you are just doing searches to use |
I actually really like the I'd be happy to write a tool to convert RipGrep's output to the patch format, but I'm not sure that's possible as-is, since The main reasons I'd prefer a patch file are because, as mentioned above, it would be nice to be able to review a large-scale change before applying it, and because patches are easily revertible, whereas reversing the search-and-replace is not (in case the replacement string already existed anywhere in the directory). One other major benefit is that patchfiles can be used as-is with multiple other tools (such as Git). It's also possible that using multiple regex tools may eventually reveal incompatibilities between them, and that a patch-based approach would be faster than re-running a complex regex twice on every line of the files that will be modified. |
@BatmanAoD I think it would be better to build a dedicated tool for such functionality. It sounds exactly like the kind of feature that will beget more features, and I'm not that interested in maintaining it. |
@lydell Here is my interactive version of your script: rgr () {
if [ $# -lt 2 ]
then
echo "rg with interactive text replacement"
echo "Usage: rgr text replacement-text"
return
fi
vim --clean -c ":execute ':argdo %s%$1%$2%gc | update' | :q" -- $(rg $1 -l ${@:3})
} You can also reuse your rg args, e.g: $ rg foo ./my-dir/ -t py
$ rgr foo bar ./my-dir/ -t py |
It looks like ruplacer has output in patch format. |
@kfir-drivenets could you add links to some solutions to your top post? My favorite would be: #74 (comment) |
Quick and dirty shell function based on #74 (comment) replace(){ rg "$1" --files-with-matches | xargs sed -i "s/$1/$2/g" } Usage:
|
For anyone looking for this feature, as I have been:
Example usage from
|
Full
|
This comment was marked as off-topic.
This comment was marked as off-topic.
I've been using sad for a while, and in the README there I discovered that ripgrep actually supports My quick-and-dirty solution (for single-line changes) has been the following little snippet to produce a sad-person's diff format:
I then usually pipe the output to delta for previewing with:
and when it looks good, I just
|
@steabert , the limitation of using diff output is that is only works inside git repos. If you want to do find and replace outside a git repo you're out-of-luck. I recommend using my From rgr foo -r boo
Do a *dry run* to replace all instances of 'foo' with 'boo' in this folder and down.
rgr foo -R boo
ACTUALLY REPLACE ON YOUR DISK all instances of 'foo' with 'boo' in this folder and down. |
@ElectricRCAircraftGuy Patch files are much older than git, and you can apply them anywhere with the |
For those who is coming late to the party, no, there is no support for replace in files, here is the link to FAQ and TL;DR to fastmod.
|
This comment was marked as off-topic.
This comment was marked as off-topic.
@Corallus-Caninus , meanwhile, have you seen my wrapper above? Use |
I am never going to add this to ripgrep. It isn't happening. Normally I would lock this issue. But folks are still posting helpful content about other approaches. So I'm going to leave this open, but I'm going to mark comments asking for this to be in ripgrep as off topic. There is no hope. It will never happen. Final decision. |
Disclaimer: I think Now that Here's the version that's a branch of Here's the version that extracts the necessary bits: https://github.com/BatmanAoD/RipPatch Note that it relies on a a branch that publishes I wanted RipPatch to respect or ignore every There's a third possible approach, which is to use either the |
Or, just use regular ripgrep commands, plus @BatmanAoD , at the risk of me sounding redundant, or self-promoting, have you tried running this to do an on-disk replacement?: rgr foo -r boo
Do a *dry run* to replace all instances of 'foo' with 'boo' in this folder and down.
rgr foo -R boo
ACTUALLY REPLACE ON YOUR DISK all instances of 'foo' with 'boo' in this folder and down. I feel like people either don't know about the wrapper I wrote, don't understand how to use it, or don't believe how easy it is to use. It is a wrapper around ripgrep and it supports all ripgrep commands, period, plus Installation instructions are at the top of the file. I plan on keeping it functional as long as Can anyone offering an alternative please tell me what problem my wrapper has yet to solve? I don't understand. I feel like if you just knew it existed, you'd use it and be done asking for an on-disk ripgrep replace option, since this is the sole purpose of my wrapper and exactly what it does. And again, it supports all ripgrep commands, exactly as ripgrep does, as well. That being said, if you're needing some sort of patch tool instead of an on-disk ripgrep-based search and replace tool, my wrapper may not be what you want (albeit, I don't know what a patch tool is or does or why someone would want one 🙂). |
@ElectricRCAircraftGuy I can install |
Yes, @ElectricRCAircraftGuy, I agree with both you and @abitrolly, 'people don't know about' your wrapper because discoverability is hard, it's not obviously supported, etc. If you put it in its own repo it will no doubt collect 'stars', seem like a 'real' thing that's visibly maintained, more people will package it even if you don't provide first-party ones, etc. |
@ElectricRCAircraftGuy Regarding making a version of Regarding your script, I haven't actually tried it, but I did know about it prior to writing my code, and I actually read through the source before posting my comment. To be honest, the primary reason I don't use your script is simply that I already have a Bash function in my personal config that works about equally well for my purposes. It does suffer from some drawbacks that your script avoids, particularly the risk of The secondary reason is that it's nontrivial to install your script and make it work on all platforms. I always install The tertiary reason is simply that Bash scripts are notoriously flaky, and your script is a lot more complex than the function I wrote with Note that the |
@abitrolly @OJFord @BatmanAoD , I appreciate the feedback. In an attempt to begin addressing your concerns, collect stars--as you said, have broader support and better tracking, etc., I've moved my https://github.com/ElectricRCAircraftGuy/ripgrep_replace If anyone wants to make a gif of its usage, feel free, and I can add it to the readme via a pull request. Otherwise, I'll make an issue to do that. |
One of the usecases that many people have is a simple search and replace in multiple files.
Usually I achieve this functionality with
xargs sed
for example withag -l 'hello' | xargs sed -i "s/hello/bye/g
.Since rg contains the replace flag it will be nice to add support for this feature by replacing in the files directly.
This will be a nice addition after #26
An example on how to do this with
sed
can be found in the comments here.#74 (comment)
The text was updated successfully, but these errors were encountered: