LinuxQuestions.org
View the Most Wanted LQ Wiki articles.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 07-23-2008, 03:05 PM   #1
lhouk
LQ Newbie
 
Registered: Apr 2004
Location: Houston, Texas USA
Distribution: Fedora 8 (mostly)
Posts: 15

Rep: Reputation: 0
Insert line on match only once with sed?


I thought this would be fairly straightforward, but it's got me stumped. The following sed command will find every blank line and insert the new line "aaaa" after each one:
Code:
sed '/^$/i\
aaaa'
But can I modify it to insert the new line only once, after just the first blank line, no matter how many blank lines are in my file? Thanks in advance to all who respond.
 
Old 07-23-2008, 06:05 PM   #2
Mr. C.
Senior Member
 
Registered: Jun 2008
Posts: 2,529

Rep: Reputation: 59
Sed can be a pain to work with.

Does this work for you:

Code:
perl -e '$/=undef; $_=<>; s/\n\n/\naaaa\n/; print $_'  datafile

Last edited by Mr. C.; 07-23-2008 at 06:06 PM.
 
Old 07-23-2008, 08:17 PM   #3
ghostdog74
Senior Member
 
Registered: Aug 2006
Posts: 2,695
Blog Entries: 5

Rep: Reputation: 241Reputation: 241Reputation: 241
Code:
awk 'NF==0{print;print "insert line";next}1' file
 
Old 07-23-2008, 10:58 PM   #4
pixellany
LQ Veteran
 
Registered: Nov 2005
Location: Annapolis, MD
Distribution: Arch/XFCE
Posts: 17,802

Rep: Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728
I don't see a simple way in SED. (Perhaps Mr. C and ghostdog74 did not either.....)

SED provides a mechanism for specifying which occurrence of a pattern to act on, but it works line by line.

Note that "i" will insert your new text BEFORE the line matching the pattern. To insert after, you want "a" (append).

Best SED (and AWK) tutorial here:
http://www.grymoire.com/Unix/Sed.html#
 
Old 07-23-2008, 11:17 PM   #5
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 12,229

Rep: Reputation: 1019Reputation: 1019Reputation: 1019Reputation: 1019Reputation: 1019Reputation: 1019Reputation: 1019Reputation: 1019
Just goes to prove - use the (best) tool for the job. Hammers don't make good screw-drivers.
 
Old 07-24-2008, 12:05 AM   #6
pixellany
LQ Veteran
 
Registered: Nov 2005
Location: Annapolis, MD
Distribution: Arch/XFCE
Posts: 17,802

Rep: Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728
Quote:
Originally Posted by syg00 View Post
Hammers don't make good screw-drivers.
Well, now.....that depends on the screw, doesn't it........ In my motorcycle repair days, we had a saying: "Get a bigger hammer". With what we were dealing with, that was the right answer surprisingly often.

Bash scripting is like having the world biggest collection of hammers---all sizes. We all have our favorite that we grab first.
 
Old 07-24-2008, 07:31 AM   #7
Kenhelm
Member
 
Registered: Mar 2008
Location: N. W. England
Distribution: Mandriva
Posts: 329

Rep: Reputation: 140Reputation: 140
This inserts the newline "aaaa" only after the first blank line.
Code:
sed '1,/^$/ {/^$/a\
aaaa
}'
 
Old 07-24-2008, 08:09 AM   #8
pixellany
LQ Veteran
 
Registered: Nov 2005
Location: Annapolis, MD
Distribution: Arch/XFCE
Posts: 17,802

Rep: Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728
Neat....

I didn't know that the range syntax could be nested like that
 
Old 07-24-2008, 09:33 AM   #9
lhouk
LQ Newbie
 
Registered: Apr 2004
Location: Houston, Texas USA
Distribution: Fedora 8 (mostly)
Posts: 15

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by Kenhelm View Post
This inserts the newline "aaaa" only after the first blank line.
Code:
sed '1,/^$/ {/^$/a\
aaaa
}'
That's exactly what I was looking for! Thank you!

And pixellany, you are quite right:

Quote:
Originally Posted by pixellany View Post
...Note that "i" will insert your new text BEFORE the line matching the pattern. To insert after, you want "a" (append)...
I wrote "after" in my original post, when I meant to say "before". But Kenhelm's code works just as well with "i" as with "a".

Also, thanks to Mr. C and ghostdog74 for their responses. I appreciate the help.
 
Old 07-24-2008, 12:07 PM   #10
Mr. C.
Senior Member
 
Registered: Jun 2008
Posts: 2,529

Rep: Reputation: 59
The range isn't exactly nested; the command is

[2addr] function-list

in this case the [2addr] is the range line 1 to the first blank line. The function list looks like:

{
func1
func2
...
}

and this list contains only one function, which itself looks like:

[1addr]a

where [1addr] specifies any lines matching /^$/.

I used to love working out all sorts of problems with sed, but now no longer have the patience for it.
Nice job Kenhelm.

ps. I'm still awaiting someone to solve the sed palindrome checker I've challenge sed masters with several times. :-)

Last edited by Mr. C.; 07-24-2008 at 12:09 PM.
 
Old 07-24-2008, 12:17 PM   #11
pixellany
LQ Veteran
 
Registered: Nov 2005
Location: Annapolis, MD
Distribution: Arch/XFCE
Posts: 17,802

Rep: Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728
Yes, I was sloppy when said range. What is "nested" here is the <<address--action>> functionality of SED. Range is a special case of address.

Nesting:

<<address---
<<address--action>>
>>

Can this nesting go deeper? For example:
<<range---
<<subrange---
<<address---action>>
>>
>>

Where is the Palindrome problem posted? (Somewhere I proposed a thread on scripting puzzles--should we revive that idea?)
 
Old 07-24-2008, 01:11 PM   #12
Mr. C.
Senior Member
 
Registered: Jun 2008
Posts: 2,529

Rep: Reputation: 59
I've not posted the palindrome problem officially, but have mentioned it several times. Basically, the challenge is to make a sed script that recognizes any palindrome and outputs Yes, if it is, and No if it is not.

The range is in the definition of a 2addr (which means 0, 1, or 2 addresses), and addresses take a couple of forms, such as line number, or a pattern. Example 2addr's are 4, or 3,4, or 5,/somepat/, or /pat2/,$, etc.

Can sed "nest"; sure. As long as you live within its grammer, you can do what you're asking about:

Code:
$ cat in
Section AAA
        var1 = abba
        var2 = baab
        var3 = abab
EndSection

Section BBB
        var1 = nisse
        var2 = lasse
        var3 = salle

EndSection

$ cat sed.script2
1,$ {
=
/Section/ {
p
/End/ {
a\
This is the end
}
}
}

$ sed -nf sed.script2 in
1
Section AAA
2
3
4
5
EndSection
This is the end
6
7
Section BBB
8
9
10
11
12
EndSection
This is the end

Last edited by Mr. C.; 07-24-2008 at 01:13 PM.
 
Old 07-24-2008, 02:42 PM   #13
pixellany
LQ Veteran
 
Registered: Nov 2005
Location: Annapolis, MD
Distribution: Arch/XFCE
Posts: 17,802

Rep: Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728Reputation: 728
Just ran some more tests....

Not only can you nest address--action pairs, but the subaddresses can overlap.

eg:
sed '1,6{1,3<do something>;2,5<do something else>;4,6<do more stuff>}' file

If each action is a change, then they happen in order---ie lines 1 thru 3 get changed, and then the changes for 2 thru 5 get applied, etc.

But, if--eg-- the action for 2,5 is delete, then the next statement acts on what WAS lines 4,6.

WOW!!! The opportunities to write obfuscated SED code just went way up.......
 
Old 07-24-2008, 02:50 PM   #14
Mr. C.
Senior Member
 
Registered: Jun 2008
Posts: 2,529

Rep: Reputation: 59
Exactly. Just think of 2addr or 1addr as asking "does the current line number or pattern (space) match the address(es) specified in 2addr or 1addr? ... If so, do stuff".

Last edited by Mr. C.; 07-24-2008 at 02:53 PM.
 
Old 07-25-2008, 03:07 AM   #15
Kenhelm
Member
 
Registered: Mar 2008
Location: N. W. England
Distribution: Mandriva
Posts: 329

Rep: Reputation: 140Reputation: 140
An answer to Mr. C.'s sed palindrome checker problem:-
Code:
#!/bin/bash
# If $1 is a palindrome output 'Yes'; otherwise output 'No'
echo $1 | sed 's/.*/&\n&\nNo\nYes/' |  # Make 4 lines: $1/$1/No/Yes
sed '2 {/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.// }' | # 'rev' line 2
sed '$!N; /^\(.*\)\n\1$/!P; D' |                    # Emulate 'uniq'
sed -n '3p'                                         # Output line 3
The method:-
Set up 4 lines,
$1
$1
No
Yes

Emulate 'rev' only on line 2 (e.g. "abcde" becomes "edcba")

Emulate 'uniq': if $1 is a palindrome line 2 is deleted so "Yes" moves up from line 4 to replace "No" on line 3.

Output line 3.

The emulations of 'rev' and 'uniq' are from
'Useful One-line Scripts For sed' Compiled by Eric Pement
http://sed.sourceforge.net/sed1line.txt
 
  


Reply

Tags
insert, sed


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
sed insert # at the beginning of a line ilo Linux - Newbie 17 12-19-2012 08:21 AM
grep/sed/awk - find match, then match on next line gctaylor1 Programming 3 07-11-2007 08:55 AM
sed display line after pattern match inonzi_prowler Linux - Software 3 02-19-2007 01:47 PM
SED - replace / insert furquan Programming 5 03-01-2006 06:58 PM
Insert character into a line with sed? & variables in sed? jago25_98 Programming 5 03-11-2004 06:12 AM


All times are GMT -5. The time now is 05:15 PM.

Main Menu
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
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration