LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - General (https://www.linuxquestions.org/questions/linux-general-1/)
-   -   Find & Replace string in multiple files (https://www.linuxquestions.org/questions/linux-general-1/find-and-replace-string-in-multiple-files-782417/)

Rudy 01-15-2010 10:52 AM

Find & Replace string in multiple files
 
The title of my post says it all.

After hours (literally) of searching the web and reading man pages, I think I've come up with the following:

Code:

find . -exec grep 'path/to/file' -print | xargs -0 -I new_path mv {this is where I get confused}
So my code above is incomplete, obviously. In order to finish replacing the string, I need to mv the new file into the old file's spot. How do I do this, by incorporating it into my line of code?

And do I need to modify my code at all? Any thoughts, help, or suggestions would be appreciated.

- David

affinity 01-15-2010 11:08 AM

Sed has a switch for editing files in place, its -i. This allows it to run the arguments on the file and make changes without having to create a copy and then later move the copy to the original. It also uses the -f switch to use commands from a file to be executed. A single sed command to replace one instance of text with another would look like this: sed -i 's:{target}:{new}:g' the :g tells sed to continue on replacing the first expression with the second until the end of file is reached, otherwise it would stop after the first occurrence. If you use multiple commands you would use -e before each one to let sed know that it's a new argument, otherwise it would treat it as part of the first argument.

Rudy 01-15-2010 11:16 AM

ahh, the -i flag! Why did I not see that in my man page... oh well. I see it in there now.

So, when do the following, I get an error:
Code:

find . -exec grep 'path/to/file' -print | sed -i 's:/path/to/file:new/path/to/file:g'
The error is...
Code:

$ sed: no input files
$ find: missing argument to `-exec'

The command I am trying to execute is "grep" so why isn't that being translated by find as a command? Or am I doing something wrong? (obviously, I am, but what?)

Thanks again,
David

affinity 01-15-2010 11:39 AM

For the sed part, you have to tell it what file is being altered after the arguments. It looks like you are trying to rename files though? If that's the case you will want to use the rename command instead. You wouldn't have to use grep to do this, using the example from the rename man page you would change the file extensions of any file with .htm to .html like this:
rename .htm .html *.htm

What exactly are you trying to do?

Rudy 01-15-2010 11:47 AM

Oops, poor choice of words in my SED example. Sorry about that.

Here's what I'm trying to do: I have file x, which contains string "y" and I want to change string "y" into string "z".

affinity 01-15-2010 12:05 PM

Ok in that case you would simply do the following:
sed -i 's:y:z:g' x

To explain that line piece by piece:
-i for editing in place
s: means you are replacing text
y is the expression being changed
z is the replacement for y
g means global, continue until end
x is the file being altered.

If you are doing this on every file in a directory, and there are no hidden files, you can use * instead of a single filename. That will run the command on EVERY file, no exceptions. So only do that if you are positive it's what you want. If there are multiple files that you want to change, but they don't share a common naming scheme or are scattered about you can make this into a function so that you just type the function name followed by the filename. You would add the function to your ~/.bashrc like so:

function myscriptname {
FILE=$1 # where the first argument given after myscriptname is file
sed -i 's:y:z:g' $FILE
}

Then you could just type the following in your shell 'myscriptname file. This is also useful in that if you have multiple expressions you want replaced in the same file you simply add another sed command directly under the original, or any other types of commands you want done to that file.

Rudy 01-15-2010 12:57 PM

holy mackrell! That's it?

I just ran it, and that worked like a charm. I was trying to make things way too complicated here... thanks a ton.

affinity 01-15-2010 12:59 PM

Quote:

Originally Posted by Rudy (Post 3827807)
holy mackrell! That's it?

I just ran it, and that worked like a charm. I was trying to make things way too complicated here... thanks a ton.

Yea that's it, once you figure out the right tool for the job things are much easier :D. Your welcome!

GrapefruiTgirl 01-15-2010 12:59 PM

Quote:

Originally Posted by Rudy (Post 3827807)
I was trying to make things way too complicated here...

Sometimes I wonder if that's my raison d'etre.. It's very easy to over-complicate things (I know this from first-hand experience, but seem to need to relearn it regularly) ;) by assuming something involves much more than it actually might. LOL.

Rudy 01-15-2010 02:26 PM

Well, I thought this had solved everything. Guess not.

Round 1 of replacements worked. Round 2? failed. Right now, I'm trying to replace a pretty complicated string. Here's my exact command:

Code:

sed -i 's.<img border="0" width="738" src="images/esa_logo.jpg" style="position: absolute; padding-left: 5px;" alt="Home" id="ESA logo"/>.<img border="0" width="738" src="images/esa_logo.jpg" style="position: relative; padding-left: 5px;" alt="Home" id="ESA logo"/>.g' *
And here's my error message:
Code:

sed: -e expression #1, char 131: unknown option to `s'
Any idea why?

GrapefruiTgirl 01-15-2010 03:07 PM

I haven't got my glasses on at this moment, but at a glance: since you're using a period as the sed special character, you probably need to escape the periods within the LHS and RHS of the expression. (such as .jpg should be \.jpg)

If this isn't it, I'll have another look after if nobody else has offered advice.

PS - use a special character that does not appear in the LHS or RHS,such as maybe a % sign, or @ sign.

Sasha

affinity 01-15-2010 10:40 PM

Take a look at this site, it's a quick run through of using sed. I linked to the section about delimiters.

H_TeXMeX_H 01-16-2010 07:14 AM

Try

Code:

sed -i 's|<img border="0" width="738" src="images/esa_logo.jpg" style="position: absolute; padding-left: 5px;" alt="Home" id="ESA logo"/>|<img border="0" width="738" src="images/esa_logo.jpg" style="position: relative; padding-left: 5px;" alt="Home" id="ESA logo"/>|g' *

Maskkkk 04-15-2010 07:49 AM

I've been looking at this thread, now say I wanna do the same thing as Rudy only I want to do it recursively on all of the files in a certain directory.

Here is what I've got so far:

Code:

find . "*.js" -exec sed -i s/jstestdriver\.console\.log.*;//g ;
But then I get the error:

Code:

sed: no input files

catkin 04-15-2010 08:10 AM

Quote:

Originally Posted by Maskkkk (Post 3936357)
I've been looking at this thread, now say I wanna do the same thing as Rudy only I want to do it recursively on all of the files in a certain directory.

Here is what I've got so far:

Code:

find . "*.js" -exec sed -i s/jstestdriver\.console\.log.*;//g ;
But then I get the error:

Code:

sed: no input files

You need find's special symbol "{}" (without the quotes) which find replaces with the found file name and you need to escape the ";" or it is seen by the shell as a command terminator
Code:

find . "*.js" -exec sed -i s/jstestdriver\.console\.log.*;//g {} \;


All times are GMT -5. The time now is 09:53 AM.