LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
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 10-08-2020, 02:09 PM   #1
mackowiakp
Member
 
Registered: Jun 2014
Location: Poland/Gdynia
Distribution: Mageia 9, SH4, Debian
Posts: 367

Rep: Reputation: 8
sed stop insert the line after the first occurrence of the pattern


Lets take such text file named "/tmp/test":

Code:
yyyy-1
xxxx-2
xxxx-3
zzzz-4
xxxx-5
I want to insert additional line containing "aaaa-6" before first occurrence of line containing string "xxxx" at the beginning of line. But only one time, as I wrote at first occurrence.

For this purpose I want to use the script like this:

Code:
#!/bin/sh

entry="aaaa-6"
sed -i "/^xxxx*/a $entry" /tmp/test
But this script insert after each occurrence of pattern.
Any idea how to stop sed after first occurrence?
Notice that /bin/sh is used (busybox) not bash.
 
Old 10-08-2020, 04:35 PM   #2
boughtonp
Senior Member
 
Registered: Feb 2007
Location: UK
Distribution: Debian
Posts: 3,600

Rep: Reputation: 2546Reputation: 2546Reputation: 2546Reputation: 2546Reputation: 2546Reputation: 2546Reputation: 2546Reputation: 2546Reputation: 2546Reputation: 2546Reputation: 2546

Sed works on individual lines at a time - if you're to working on multiple lines, a different tool might be a better fit.

However, GNU sed does have -z to treat the line delimiter as nul char instead of newlines; I don't know if Busybox sed has that, but if it does you can combine it with passing 1 to s/// to instruct it to substitute once, like so:
Code:
sed -z 's/\nxxx[^\n]*\n/\nINSERTED\0/1' input-file
The \0 includes the matched text in the replacement, making this a prepend operation. (Swap places with \0 and \n to make it an append instead.)


If the -z flag isn't available, but using other tools is an option, awk can easily use a flag as part of its condition:
Code:
awk '/^xxx/ && !ins {print "INSERTED";ins=1};{print}' input-file
(To make that an append rather than a prepend, move the final {print} action to the start.)


Last edited by boughtonp; 10-08-2020 at 04:45 PM.
 
Old 10-08-2020, 09:46 PM   #3
berndbausch
LQ Addict
 
Registered: Nov 2013
Location: Tokyo
Distribution: Mostly Ubuntu and Centos
Posts: 6,316

Rep: Reputation: 2002Reputation: 2002Reputation: 2002Reputation: 2002Reputation: 2002Reputation: 2002Reputation: 2002Reputation: 2002Reputation: 2002Reputation: 2002Reputation: 2002
Quote:
Originally Posted by mackowiakp View Post
Code:
#!/bin/sh

entry="aaaa-6"
sed -i "/^xxxx*/a $entry" /tmp/test
But this script insert after each occurrence of pattern.
Any idea how to stop sed after first occurrence?
The "a" in the sed command means "append". There is an "i" command, which inserts before a line.

I am not sure if sed can be asked to perform the insertion only at the first occurrence of the line pattern. Check the sed manual (link in my signature).
 
Old 10-08-2020, 10:48 PM   #4
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 21,128

Rep: Reputation: 4121Reputation: 4121Reputation: 4121Reputation: 4121Reputation: 4121Reputation: 4121Reputation: 4121Reputation: 4121Reputation: 4121Reputation: 4121Reputation: 4121
Normally one would simply use q to stop after a sed sub-command. Doesn't work here because:
- the append consumes everything as its text - including the " ; q}". Didn't know that until I just tested.
- even if it did work, the quit will truncate the file due to the use of "-i".

The only way I could get it done was to read the entire file into the pattern space and change only the first occurrence which sed supports (i.e. don't use append at all).

Last edited by syg00; 10-08-2020 at 10:50 PM.
 
Old 10-09-2020, 01:25 AM   #5
mackowiakp
Member
 
Registered: Jun 2014
Location: Poland/Gdynia
Distribution: Mageia 9, SH4, Debian
Posts: 367

Original Poster
Rep: Reputation: 8
Quote:
Originally Posted by berndbausch View Post
The "a" in the sed command means "append". There is an "i" command, which inserts before a line.

I am not sure if sed can be asked to perform the insertion only at the first occurrence of the line pattern. Check the sed manual (link in my signature).
Yep. a stands for append, i stands for insert. But the output result is the same in both cases.
 
Old 10-09-2020, 02:26 AM   #6
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,850

Rep: Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309
something like this?:
Code:
sed '/pattern/{a something;q}'
 
Old 10-09-2020, 03:51 AM   #7
mackowiakp
Member
 
Registered: Jun 2014
Location: Poland/Gdynia
Distribution: Mageia 9, SH4, Debian
Posts: 367

Original Poster
Rep: Reputation: 8
Quote:
Originally Posted by pan64 View Post
something like this?:
Code:
sed '/pattern/{a something;q}'

My code:
Code:
#!/bin/sh

entry="aaaa-6"
sed "/^xxxx*/{a $entry;q}" /tmp/test
Returns :
Code:
sed: unterminated {
double quote because variable is used inside sed arguments.
 
Old 10-09-2020, 03:52 AM   #8
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 21,128

Rep: Reputation: 4121Reputation: 4121Reputation: 4121Reputation: 4121Reputation: 4121Reputation: 4121Reputation: 4121Reputation: 4121Reputation: 4121Reputation: 4121Reputation: 4121
See my prior post.
 
Old 10-09-2020, 04:49 AM   #9
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,794

Rep: Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201
You can read the remainder of the file, so the condition is not hit again.
As multi-lined portable sed code:
Code:
#!/bin/sh
entry="aaaa-6"
sed '
/^xxxx/{
s/$/\
'"$entry"'/
:L
$!N
$!bL
}
' input-file
For some reason an a command turns into an i command when lines are added with N. So I emulated the a command by an s command.

Last edited by MadeInGermany; 10-09-2020 at 05:55 AM. Reason: ^ added
 
1 members found this post helpful.
Old 10-09-2020, 10:53 AM   #10
mackowiakp
Member
 
Registered: Jun 2014
Location: Poland/Gdynia
Distribution: Mageia 9, SH4, Debian
Posts: 367

Original Poster
Rep: Reputation: 8
Yep @MadeInGermany. WORKS !. But...it place $entry after the first line match, not before. Any modification?
 
Old 10-09-2020, 01:13 PM   #11
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,794

Rep: Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201
Changed s command to emulate an i command
Code:
sed '
/^xxxx/{
s/^/'"$entry"'\
/
:L
$!N
$!bL
}
' input-file
 
1 members found this post helpful.
Old 10-09-2020, 02:14 PM   #12
mackowiakp
Member
 
Registered: Jun 2014
Location: Poland/Gdynia
Distribution: Mageia 9, SH4, Debian
Posts: 367

Original Poster
Rep: Reputation: 8
THX! WORKS as expected !
 
Old 12-27-2021, 01:45 PM   #13
shruggy
Senior Member
 
Registered: Mar 2020
Posts: 3,670

Rep: Reputation: Disabled
GNU sed knows some useful tricks like the 0 address:
Code:
sed -e "0,/xxxx/{//i$entry" -e\} input-file
Considering the file is being edited in place, I'd rather use ed or vi/ex here. See Exercise 2.2 in Zintz' tutorial.
Code:
vim -es +"0/xxxx/s/^/$entry\r/|x" input-file
I believe most distros symlink ex to vi, so that ex -s would be the same as vim -es above.

You cannot make a one-liner with ed, but a HERE document looks simple and clean:
Code:
<<! ed -s input-file
/xxxx/i
$entry
.
wq
!
 
  


Reply

Tags
sed, shell



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] replace only 1st occurrence of pattern using sed, or whatever works. BW-userx Programming 15 07-12-2019 06:57 AM
SED one-liner for remove or comment out a line matching a certain pattern after the first line match Honest Abe Linux - Newbie 8 10-04-2018 05:36 AM
Read first line in a file and append it to first occurrence of the search string and Repeat until EOF hruday Linux - Newbie 6 11-26-2017 10:42 AM
[SOLVED] sed to display the pattern string, the line above it and the first line of that para rockie321 Linux - Newbie 3 04-03-2011 02:48 PM
sed: delete lines after last occurrence of a pattern in a file zugvogel Programming 4 11-17-2009 01:49 AM

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

All times are GMT -5. The time now is 04:05 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