ChatGPT解决这个技术问题 Extra ChatGPT

Find and replace with sed in directory and sub directories

I run this command to find and replace all occurrences of 'apple' with 'orange' in all files in root of my site:

find ./ -exec sed -i 's/apple/orange/g' {} \;

But it doesn't go through sub directories.

What is wrong with this command?

Here are some lines of output of find ./:

./index.php
./header.php
./fpd
./fpd/font
./fpd/font/desktop.ini
./fpd/font/courier.php
./fpd/font/symbol.php
could you run find ./ and post some sample output? And the directory strucuture please. edit: thanks!
Hm your find is correct, works for me with subdirs.
How do you know it does not process subdirectories?
because it gives these errors: sed: couldn't edit ./fpd: not a regular file sed: couldn't edit ./fpd/font: not a regular file sed: couldn't edit ./fpd/font/makefont: not a regula
oh... i grep for apple and nothing found.they all were replaced. ;) thank you . you opened my eyes !!!

P
Philippe Fanaro

Your find should look like that to avoid sending directory names to sed:

find ./ -type f -exec sed -i -e 's/apple/orange/g' {} \;

You may need to change sed -i 's/apple/orange/g' to sed -i '' 's/apple/orange/g' to make this work.
-i takes an argument: the extension used to save the temporary file. In GNU sed, looks like there's no space between -i and its argument, but in BSD sed there is… so BSD -i '' 's/foo/bar/' is equivalent to GNU -i 's/foo/bar/.
Actually adding -e does not work on Mac OS. touch a b c d e followed by the command above produces a directory listing like this: a a-e b b-e c c-e d d-e e e-e.
For Mac OS, this answers stackoverflow.com/questions/19242275/… the RE error: illegal byte sequence
For fish shell users, be sure to quote the empty braces '{}', because fish automatically expands the empty braces if not quoted.
J
Julius

For larger s&r tasks it's better and faster to use grep and xargs, so, for example;

grep -rl 'apples' /dir_to_search_under | xargs sed -i 's/apples/oranges/g'

Thanks for this answer, it was very helpful! If in a git repository, it's even faster using git grep -l 'apples' | xargs sed -i 's/apples/oranges/g'
If on macos, use xargs sed -i '' 's/apples/oranges/g'
If you're trying to replace something with a forward slash in it, you can use sed with | rather than /, e.g. ... xargs sed -i 's|mduuid/apples|mduuid/oranges|g' stackoverflow.com/questions/40714970/…
p
pat-s

Since there are also macOS folks reading this one (as I did), the following code worked for me (on 10.14)

egrep -rl '<pattern>' <dir> | xargs -I@ sed -i '' 's/<arg1>/<arg2>/g' @

All other answers using -i and -e do not work on macOS.

Source


On the mac the accepted answer does work [kind of] - but it spits out 'duplicate' files with -e which would need to be removed / piped into another command (to use verbatim). This method is better though and is still working for me (on 11.2.3)
s
shadyyx

This worked for me:

find ./ -type f -exec sed -i '' 's#NEEDLE#REPLACEMENT#' *.php {} \;

original question doesn't restrict to *.php files, there's also an .ini one
The unquoted *.php is really incorrect; you just got lucky that it didn't get expanded in the starting directory because you didn't happen to have any matching files there.
Restriction on file name could be obtained with -name *.php on the find command.
r
rocLv
grep -e apple your_site_root/**/*.* -s -l | xargs sed -i "" "s|apple|orage|"

B
Billal Begueradj

I think we can do this with one line simple command

for i in `grep -rl eth0 . 2> /dev/null`; do sed -i ‘s/eth0/eth1/’ $i; done

Refer to this page.


C
Colin D

Found a great program for this called ruplacer

https://github.com/dmerejkowsky/ruplacer

Usage

ruplacer before_text after_text # prints out list of things it will replace
ruplacer before_text after_text --go # executes the replacements

It also respects .gitignore so it won't mess up your .git or node_modules directories (find . by default will go into your .git directory and can corrupt it!!!)


ฉัตรชัย สิทธิวงค์

In linuxOS:

sed -i 's/textSerch/textReplace/g' namefile

if "sed" not work try :

perl -i -pe 's/textSerch/textReplace/g' namefile

he wants to find all files in sub directories contain that string and replace, not only a single file