LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices


Reply
  Search this Thread
Old 06-20-2012, 11:50 AM   #1
jebradl
LQ Newbie
 
Registered: Feb 2011
Posts: 5

Rep: Reputation: 0
Searching and replacing strings in groups of files


I realize that this has been covered numerous times in the past, but I can't seem to get any of the previous suggestions to work. I've tried various things with grep and sed.

I am trying to replace a string of text "line-width = 6 \in"
with the string "line-width = 7.8 \in"
in 500+ lilypond files so that they display better on my nook. The problem seems to be the backslash, but trying it with a double backslash doesn't improve things.
Thank you.
 
Old 06-20-2012, 11:59 AM   #2
whizje
Member
 
Registered: Sep 2008
Location: The Netherlands
Distribution: Slackware64 current
Posts: 594

Rep: Reputation: 141Reputation: 141
Replace 6 with 7.8
Code:
bash-4.2$ echo "line-width = 6 \in" | sed 's/6/7.8/'
line-width = 7.8 \in
 
Old 06-20-2012, 12:07 PM   #3
MensaWater
LQ Guru
 
Registered: May 2005
Location: Atlanta Georgia USA
Distribution: Redhat (RHEL), CentOS, Fedora, CoreOS, Debian, FreeBSD, HP-UX, Solaris, SCO
Posts: 7,831
Blog Entries: 15

Rep: Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669
Sometimes you need to break the problem into pieces. You can use fgrep without the backslash but with double quotes to find the pattern in your files. You can then use sed with backslashes to esccape the lines and make them come out right:

Code:
for file in $(fgrep -l "6 \in" *)
do echo $file
sed -e 's/6 \\in/7.8 \\in/g' $file >new$file
mv new$file $file
done
The -l tells fgrep to simply list files that match. The loop will make the change for every file found by fgrep.
 
1 members found this post helpful.
Old 06-21-2012, 11:39 AM   #4
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
The best thing to do is try to avoid the problem area entirely. You don't necessarily need to use the whole string in the sed command.

Code:
sed '/line-width/ s/= 6/= 7.8/'
This first finds lines that contain the phrase "line-width", then replaces "= 6" with "= 7.8" in those lines.

In fact, if the text you want to change is all on a single line, with nothing else that needs to be preserved, why not just replace the entire line?

Code:
sed '/line-width/ c line-width = 7.8'
Edit: BTW, you can use globbing patterns to feed sed multiple files at once, and the -i option to edit them in place. Be sure not to enable it until you've thoroughly tested your solution, of course.

Last edited by David the H.; 06-21-2012 at 11:49 AM. Reason: as written
 
1 members found this post helpful.
Old 06-21-2012, 11:45 AM   #5
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
Quote:
Originally Posted by MensaWater View Post
Code:
for file in $(fgrep -l "6 \in" *)
do
You oughta know by now...Don't Read Lines With For!
 
Old 06-22-2012, 01:07 AM   #6
jebradl
LQ Newbie
 
Registered: Feb 2011
Posts: 5

Original Poster
Rep: Reputation: 0
Even though I shouldn't have read the line with 'for' it solved my problem.
Thank you.
 
Old 06-22-2012, 08:40 AM   #7
MensaWater
LQ Guru
 
Registered: May 2005
Location: Atlanta Georgia USA
Distribution: Redhat (RHEL), CentOS, Fedora, CoreOS, Debian, FreeBSD, HP-UX, Solaris, SCO
Posts: 7,831
Blog Entries: 15

Rep: Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669
Quote:
Originally Posted by David the H. View Post
You oughta know by now...Don't Read Lines With For!
for has worked for years for me and no matter how often you post this I'll likely continue doing it.
 
Old 06-22-2012, 08:43 AM   #8
schneidz
LQ Guru
 
Registered: May 2005
Location: boston, usa
Distribution: fedora-35
Posts: 5,326

Rep: Reputation: 919Reputation: 919Reputation: 919Reputation: 919Reputation: 919Reputation: 919Reputation: 919Reputation: 919
Quote:
Originally Posted by MensaWater View Post
for has worked for years for me and no matter how often you post this I'll likely continue doing it.
i do that too, but:
Code:
fgrep -l "6 \in" * | while read line
...
would handle white spaces better.
 
Old 06-22-2012, 01:17 PM   #9
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
Well, I wouldn't have to post it so often it if certain posters would stop suggesting it. Because actually, it doesn't work, at least not consistently.

With loops like the above, the user will find his script breaking at the very first file with spaces in the name. That's why you should always use a while+read loop, preferably with null separators, when working with filename lists.

The safest form of the loop would be this, using bash and gnu grep:
Code:
while IFS='' read -r -d '' file; do

	sed -i '/line-width/ c line-width = 7.8' "$file"

done < <( fgrep -lZ "6 \in" * )
Or optionally, you could store the list in an array first, then the for loop would be safe to use, as long as you expanded it with the "[@]" index and quoteed it properly. (notice too how grep is unnecessary)

Code:
files=( * )

for file in "${files[@]}"; do

	sed -i '/line-width/ c line-width = 7.8' "$file"

done
You can even bypass the array and just use the globbing form directly as the loop feed.


And as I mentioned, as long as you're using globbing anyway (and the resulting file list) isn't overly huge, you don't even need to use a loop at all. sed can handle multiple file inputs directly.

Code:
sed -i '/line-width/ c line-width = 7.8' *

Last edited by David the H.; 06-22-2012 at 01:22 PM.
 
Old 06-22-2012, 02:26 PM   #10
MensaWater
LQ Guru
 
Registered: May 2005
Location: Atlanta Georgia USA
Distribution: Redhat (RHEL), CentOS, Fedora, CoreOS, Debian, FreeBSD, HP-UX, Solaris, SCO
Posts: 7,831
Blog Entries: 15

Rep: Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669
Clearly it DOES work as it least one other person said they did it.

Preferring a number 2 pencil does NOT mean a pen doesn't work.
 
Old 06-22-2012, 03:20 PM   #11
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
That's why I added the caveat "not consistently". It only works when the conditions are exactly right, and the input doesn't contain whitespace or globbing patterns that would force breaks in undesirable locations.

Perhaps your filenames are always clean, but on an open board like this you can't assume that the person you are giving advice to has the same setup. Almost certainly some naive newbie is going to try to use it and wonder why it's not working for him, at the least, if not have some data destroyed because of it.

As long as you, or anyone else, keeps posting such poor code, I'm going to keep correcting it.

(BTW, I expect nothing but the same in return. If I post something that can potentially break things or especially cause data loss, it needs to be corrected, whatever the cost to my own ego.)

Last edited by David the H.; 06-22-2012 at 03:29 PM.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] Searching and replacing strings in a file with strings in other files xndd Linux - Newbie 16 07-29-2010 02:40 PM
Python: replacing strings in a file tonya11en Programming 2 05-19-2009 06:52 PM
replacing strings in many files using tcsh mcbenus Linux - Software 5 03-03-2008 05:50 PM
Help with sed - replacing strings thulley Linux - Software 4 08-22-2006 10:07 AM
Searching files for strings tmoorman Linux - Software 4 01-08-2004 01:46 PM

LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie

All times are GMT -5. The time now is 08:54 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration