LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
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-11-2020, 10:22 PM   #1
Johng
Member
 
Registered: Feb 2002
Location: NZ
Distribution: Kubuntu, Mint
Posts: 408

Rep: Reputation: 31
Substitute text between pattern with string using sed


I am trying to create a script to edit files using sed. I want to substitute some text between two patterns with a string generated in the script. The text to be replaced varies from file to file.

Change:
Code:
<name>some unknown text</name>
To:
Code:
<name>$newstring</name>
Any help?
 
Old 07-11-2020, 10:51 PM   #2
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,862
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
Untested:
Code:
FromName='some unknown text'
ToName='$newstring'
sed -i 's/<name>'"$FromName"'<\/name>/<name>'"$ToName"'<\/name>/' filename.xml
Or perhaps you mean this:
Code:
ToName='$newstring'
sed -i 's/<name>[^<]*<\/name>/<name>'"$ToName"'<\/name>/' filename.xml

Last edited by NevemTeve; 07-11-2020 at 10:55 PM.
 
Old 07-11-2020, 10:51 PM   #3
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 21,126

Rep: Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120
So what have you tried, and why didn't it work ?.
 
1 members found this post helpful.
Old 07-12-2020, 12:59 AM   #4
Johng
Member
 
Registered: Feb 2002
Location: NZ
Distribution: Kubuntu, Mint
Posts: 408

Original Poster
Rep: Reputation: 31
Thank you NevemTeve
The second version was just what I was looking for:
Quote:
sed -i 's/<name>[^<]*<\/name>/<name>'"$ToName$GPXname"'<\/name>/' xxxx.gpx
 
Old 07-12-2020, 02:20 AM   #5
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,790

Rep: Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201
The / delimiter conflicts here. You can chose another delimiter:
Code:
sed -i 's#<name>[^<]*</name>#<name>'"$ToName$GPXname"'</name>#' xxxx.gpx
Note that the shell variables may not contain the delimiter, or sed will get a syntax error.

Further, PCRE lets you turn the greedy * match into a non-greedy *? match.
PCRE is not (yet) supported in sed, so here is the original - perl:
Code:
perl -pe -i 's#<name>.*?</name>#<name>'"$ToName$GPXname"'</name>#' xxxx.gpx
By using perl's own variables you can even avoid any delimiter conflict...
 
Old 07-12-2020, 02:47 AM   #6
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 21,126

Rep: Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120
Negated char classes are non-greedy by definition. No need for perl or perlre.
 
Old 07-12-2020, 03:34 AM   #7
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,790

Rep: Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201
Quote:
Originally Posted by syg00 View Post
Negated char classes are non-greedy by definition. No need for perl or perlre.
Not true: by definition the [^<]* expands to the maximum. The trick is to except the < character so it cannot go beyond the < character.
 
Old 07-12-2020, 07:55 AM   #8
shruggy
Senior Member
 
Registered: Mar 2020
Posts: 3,670

Rep: Reputation: Disabled
Hmm, and what <name> tag exactly is this supposed to be? Most probably /gpx/trk/name, but you see, a GPX file also may have /gpx/name and/or /gpx/wpt/name.

Anyway, this will change the value of /gpx/trk/name:
Code:
#!/bin/sh
file="xxxx.gpx"
grep -q 'xmlns=' "$file" && ns=_: || ns=
xmlstarlet ed -u //${ns}trk/${ns}name -v "$ToName$GPXname" "$file"
//${ns}name will instead edit any <name> tag present in the GPX file.
 
Old 07-13-2020, 06:12 AM   #9
boughtonp
Senior Member
 
Registered: Feb 2007
Location: UK
Distribution: Debian
Posts: 3,599

Rep: Reputation: 2546Reputation: 2546Reputation: 2546Reputation: 2546Reputation: 2546Reputation: 2546Reputation: 2546Reputation: 2546Reputation: 2546Reputation: 2546Reputation: 2546
Quote:
Originally Posted by MadeInGermany View Post
Quote:
Originally Posted by syg00 View Post
Negated char classes are non-greedy by definition. No need for perl or perlre.
Not true: by definition the [^<]* expands to the maximum. The trick is to except the < character so it cannot go beyond the < character.
Saying "not true" is missing the point - character classes have no notion of greedy or non-greedy, they are a definition of which characters should be included/excluded.

It is the quantifier which may or not be greedy, and the quantifier doesn't care whether it is acting on a regular character class or negative character class.


The point syg00 was probably trying to make (albeit with poorly chosen words) is that, when viable, using a boundary character inside a negative character class with a greedy quantifier is almost always a better choice than using an overly permissive class with a lazy quantifier - i.e. using "[^<]*<" is better than using ".*?<" so it makes no sense to suggest the latter as an "improvement" to a working pattern (especially at the expense of clouding the important bit of the post highlighting the potential benefit of using Perl variables over Bash ones).

Of course, the ideal solution to changing markup is generally to use a markup-aware parser, such as Shruggy posted.

 
  


Reply



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
To Substitute Various String Combinations with an Empty String: Sed, Awk...? charless Linux - General 1 07-17-2019 12:43 PM
[SOLVED] sed print text between two patterns inclusive, unless a third pattern is present Turbocapitalist Programming 11 09-21-2017 03:22 PM
[SOLVED] BASH: how to substitute just one occurency of a pattern in a text file carolflb Linux - Newbie 8 11-19-2009 03:31 AM
substitute a pattern only if some other pattern is present raghu123 Programming 3 06-26-2009 06:53 AM
replace a text pattern with the reverse of another text pattern lothario Linux - Software 5 07-25-2008 02:43 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

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