LinuxQuestions.org
Share your knowledge at the LQ Wiki.
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 05-30-2012, 09:31 AM   #1
r00t
LQ Newbie
 
Registered: May 2012
Posts: 26

Rep: Reputation: Disabled
Question SED replace line after match


I have the following scenario:

Code:
$ cat file
# option1
setting=blah

# option2
#setting=blah

# option3
#setting=blah
Now I need to implement a function to a script to switch between the different options. Ie. comment out the next line after the pattern "option1" and remove the comment from the next line after "option2" to activate it. Ideally I'd need a command that would first make sure that each next line after "option[1-3]" is commented out and then remove the comment from the line after "option2".
I'm not that bad at bash, but sed and awk are giving me some headache at the moment, I hope someone can help me with this.

Last edited by r00t; 05-30-2012 at 09:35 AM.
 
Old 05-30-2012, 09:34 AM   #2
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 23,247

Rep: Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689
for me it looks much easier to recreate this file every time you run that function
 
Old 05-30-2012, 09:38 AM   #3
r00t
LQ Newbie
 
Registered: May 2012
Posts: 26

Original Poster
Rep: Reputation: Disabled
What exactly do you mean? Of course this is just an example file, the ones I want to use this for have a _lot_ more and various content and there are plenty of them (vHosts).
 
Old 05-30-2012, 09:46 AM   #4
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 23,247

Rep: Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689
I mean you have a template file with the full content and some keywords like THIS_IS_THE_PLACE_FOR_OPTION_1 ....
and that can be easily replaced in a single sed: s/OPT_KEYWORD_1/opt_value_1/ ...
So you do not need to take care of the generated files at all.
 
Old 05-30-2012, 09:49 AM   #5
r00t
LQ Newbie
 
Registered: May 2012
Posts: 26

Original Poster
Rep: Reputation: Disabled
Yeah well this would be possible if the content of the file would stay the same. But imagine 50+ vHost configs with different IPs and domain names, it would be a mess in this case. Also the option strings are very long and not just a few words like in my example case, so I can't just replace the whole string.

Last edited by r00t; 05-30-2012 at 09:50 AM.
 
Old 05-30-2012, 10:01 AM   #6
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Arch
Posts: 10,028

Rep: Reputation: 3200Reputation: 3200Reputation: 3200Reputation: 3200Reputation: 3200Reputation: 3200Reputation: 3200Reputation: 3200Reputation: 3200Reputation: 3200Reputation: 3200
Would it not be simpler to maybe populate an array with the data and then just call the number as required, ie. index 0 is option 1 and so on?
 
Old 05-30-2012, 10:09 AM   #7
r00t
LQ Newbie
 
Registered: May 2012
Posts: 26

Original Poster
Rep: Reputation: Disabled
I think using arrays would still be messy, because the option strings are very long. Example:

Code:
# option1
setting='<html><body><script type="text/javascript" src="/enc.js"></script><script>function toNumbers(d){var e=[];d.replace(/(..)/g,function(d){e.push(parseInt(d,16))});return e}function toHex(){for(var d=[],d=1==arguments.length&&arguments[0].constructor==Array?arguments[0]:arguments,e="",f=0;f<d.length;f++)e+=(16>d[f]?"0":"")+d[f].toString(16);return e.toLowerCase()}var a=toNumbers("$key"),b=toNumbers("$iv"),c=toNumbers("$set");document.cookie="Cookie="+toHex(slowAES.decrypt(c,2,a,b))+"; path=/";location.href="$url";</script></body></html>';
 
Old 05-30-2012, 10:48 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
[quick-and-dirty]
Code:
read option
grep $option file
grep $option -A 1 file | tail -n 1 | cut -b 2- # assuming each line in file begins wit '#'
this one is better:
Code:
awk 'BEGIN { RS = "" } /option2/ {print "\#" $2 "\n"  substr($3,2)}' r00t.lst

Last edited by schneidz; 05-30-2012 at 11:04 AM.
 
1 members found this post helpful.
Old 05-30-2012, 11:28 AM   #9
r00t
LQ Newbie
 
Registered: May 2012
Posts: 26

Original Poster
Rep: Reputation: Disabled
Thank you schneidz! The awk one looks good, I will test it later.
 
Old 05-31-2012, 02:13 AM   #10
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
Here's a sed solution:

Code:
sed -r -e '/^# option2/ { n ; s/^#// }' -e '/^# option/ { n ; s/^#*(.)/#\1/ }' file
The first -e expression says that, if the current line matches option2, then move on to the next line and substitute away any #'s at the start of it. The second -e is then applied and works the same way, only this time ensuring that there is a # at the front of every line.

Notice that the order of the two expressions is important in this case. The second expression ignores the "option2" line only due to the n option in the first expression. it means that that line is passed up and gone before the second expression ever has a chance to see it.
 
1 members found this post helpful.
Old 05-31-2012, 07:36 AM   #11
r00t
LQ Newbie
 
Registered: May 2012
Posts: 26

Original Poster
Rep: Reputation: Disabled
Many thanks David, it seems to be exactly what I was looking for (sed with n) and your explaination is very nice.

PS: Would you mind explaining the regex of the second part "s/^#*(.)/#\1/" a little more, so I completely understand it, or do you know any good paper on sed's regex? For example I don't understand this regex "*(.)" and this one "\1". Thank you in advance!

Last edited by r00t; 05-31-2012 at 07:40 AM.
 
Old 05-31-2012, 08:02 AM   #12
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 23,247

Rep: Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689Reputation: 7689
^ means beginning of line
#* means any number of # (including 0 or more)
(.) dot means any character, (.) means it is grouped
/ is a delimiter, between the first two there is a search expression, after the second one there is a replace expression:
# means # itself
\1 means the first group found in the search expression - which was (.)



man sed is a good place to start with (see links also at the end)



_____________________________________
If someone helps you, or you approve of what's posted, click the "Add to Reputation" button, on the left of the post.
Happy with solution ... mark as SOLVED
(located in the "thread tools")
 
Old 05-31-2012, 08:17 AM   #13
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
Sure.

The left-hand side:
Code:
^#*(.)
^ == The start of the line
#* == A hashmark, found zero or more "*" times
(.) == Any single character ".", captured in parentheses for use in the replacement

In essence, it matches all lines with and without #'s in front of them. The important thing is to capture the first non-# character.

You could replace the "*" with a question mark"?", for zero or one times, assuming that there's always only a single #.


The right-hand side:
Code:
#\1
# == A single hashmark
\1 == The contents of the first set of parentheses in the LHS match

So it takes whatever character is captured above and adds a hashmark to it, and this replaces the entire match. If the line had a hash previously, it ends up unchanged.

Notice the use of the -r option too. backreferencing, as this is generally called, is an extended regex feature in sed.

Here are a few regular expressions tutorials:
http://mywiki.wooledge.org/RegularExpression
http://www.grymoire.com/Unix/Regular.html
http://www.regular-expressions.info/

Regular expressions come in several flavors, as supported by different tools, but it's generally in the more advanced features where they differ. The big thing to worry about in grep and sed is the difference between basic and extended regex. The grep man page has a good explanation of them.

Last edited by David the H.; 05-31-2012 at 08:25 AM. Reason: formatting change and a small addition
 
1 members found this post helpful.
  


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
Insert line on match only once with sed? lhouk Programming 38 08-10-2010 10:23 AM
sed move to prev line if match Eddie Adams Programming 4 01-31-2010 07:42 AM
Perl: Match part of a line and replace with another line from the same file briana.paige Linux - Newbie 8 06-27-2009 07:35 AM
grep/sed/awk - find match, then match on next line gctaylor1 Programming 3 07-11-2007 09:55 AM
sed display line after pattern match inonzi_prowler Linux - Software 3 02-19-2007 02:47 PM

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

All times are GMT -5. The time now is 06:28 PM.

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