Skip to content
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 recursive search and replace #62

Open
jrmuizel opened this issue Jan 14, 2020 · 17 comments
Open

Add support for recursive search and replace #62

jrmuizel opened this issue Jan 14, 2020 · 17 comments
Labels
M-needs triage Meta: Maintainer label me!

Comments

@jrmuizel
Copy link

It would be nice to able to do a search and replace on an entire tree of files.

@chmln
Copy link
Owner

chmln commented Mar 5, 2020

@jrmuizel not opposed to this at all, provided the feature request gains enough popularity

@heyakyra
Copy link

heyakyra commented Aug 4, 2020

In the meantime:
rg --files-with-matches <find> | xargs sd <find> <replace-with>

@pickfire
Copy link

pickfire commented Aug 4, 2020

I do sd <find> <replace-with> src/**.

@srid
Copy link

srid commented Jan 22, 2021

Or use find/xargs:

# Replace in all markdown files recursively
find . -name \*.md -print0 | xargs -0 sd <find> <replace-with>

@LPGhatguy
Copy link

LPGhatguy commented May 17, 2021

Keeping within the RIIR toolchain, fd works pretty well here:

fd -X sd <find> <replace-with> {} ";" "\.md$"

@mx-psi
Copy link

mx-psi commented Feb 16, 2022

not opposed to this at all, provided the feature request gains enough popularity

This is the issue with the most ':+1:' on this repository, so I think it's definitely popular 😄. Any chance this gets implemented?

Maybe it's already implemented by #109, but I fail to see how it works if that's the case, sd <find> <replace-with> ./** only replaces the files on the top-level directory for me.

@tshepang
Copy link
Contributor

tshepang commented Jul 8, 2022

I prefer...

sd old new $(fd)

@colemickens
Copy link

This is a constant, constant sore spot of sd for me. I don't want to have to worry about the number of cli args, shell globbing, etc, I just want a reliable tool for search/replace. sd is so close, other than missing this?

@colemickens
Copy link

also, sd old new $(fd) is definitely not shell safe.

@tshepang
Copy link
Contributor

tshepang commented Nov 5, 2022

what are the risks

@colemickens
Copy link

set -x 
f="/tmp/test/file name"
mkdir -p /tmp/test
cd /tmp/test
echo "old old" > "$f"
sd old new $(fd)
cat "$f"

results in:

❯ ./script
+ f='/tmp/test/file name'
+ mkdir -p /tmp/test
+ echo 'old old'
+ cd /tmp/test
++ fd
+ sd old new file name
Error processing file: No such file or directory (os error 2)
Error processing name: No such file or directory (os error 2)
+ cat '/tmp/test/file name'
old old

and of course quoting $(fd) doesn't work, etc. trying to "solve" this quickly ends up in multiple stackoverflow tabs and resorting to esoteric shell/bash knowledge to handle pathing and spaces and null characters and xarg syntax and on and on.

not to mention, if fd returns too many entries, etc.

Relying on bash-y shells to deal with strings and globing is almost always unfortunate.

@tshepang
Copy link
Contributor

tshepang commented Nov 6, 2022

Oh, thanks for that.

I actually use fish, and that explains why I don't get that error. I made a bash example because it has a much larger user base. For fish, it is...

sd old new (fd)

@CosmicHorrorDev CosmicHorrorDev added the M-needs triage Meta: Maintainer label me! label May 17, 2023
@colemickens
Copy link

colemickens commented Aug 28, 2023

Of course I've commented here before. I also don't really know how to use this, without looking some shell invocation every single time, when the target directory has so many files that it's too many to pass as program arguments.

this workaround feels like something, but it does work: #62 (comment)

@NoahTheDuke
Copy link

NoahTheDuke commented Aug 28, 2023

You can use fd to narrow the search to your chosen filetypes:

fd .clj -x sd <find> <replace-with>

-x executes sd on each file found, instead of on all files at once. Unless you're trying to replace in hundreds of thousands of files, this should work for all use-cases.

@colemickens
Copy link

Nice @NoahTheDuke that's definitely a simpler construction that I have a chance of remembering. Thank you for noting it!

@cdbennett
Copy link

Automatic recursive by default search/replace is what I expected after using ripgrep (rg) and falling in love with it.

When I first tried sd I was shocked to see it doesn't have also a recursive option, because getting a concise one-liner to search-and-replace across a whole project was what I'm looking for as a better sed.

However, an automatic recursive search and replace is also dangerous, especially with such a concise command syntax. This is where sd differs from ripgrep (which is read-only and non destructive). For example, if you are in the root directory or home directory and you do a recursive search and replace (maybe you meant to run fd doc Downloads and you ran sd doc Downloads instead ...), you might corrupt all kinds of files in the blink of an eye.

I would suggest that sd should at least require a flag to enable recursive operation like "-r | --recursive" instead of allowing simply sd a b to unleash changes on the entire directory tree.

@matu3ba
Copy link

matu3ba commented Apr 3, 2024

Windows Powershell workaround for missing xargs via filter:

filter xargs { & $args[0] ($args[1..$args.length] + $_) }

Usage:

rg -l -F WeirdFnName | xargs sd WeirdFnName BetterFnName

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
M-needs triage Meta: Maintainer label me!
Projects
None yet
Development

No branches or pull requests