LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Server
User Name
Password
Linux - Server This forum is for the discussion of Linux Software used in a server related context.

Notices


Reply
  Search this Thread
Old 09-28-2020, 09:19 AM   #1
luw
LQ Newbie
 
Registered: Jan 2007
Location: greater nyc area
Distribution: ubuntu10 LTS, opensolaris 5.11, tinycore 3.x
Posts: 19

Rep: Reputation: 0
sed expression selecting globally, trying to pick out sections in a file


Good morning I am getting overwhelmed with this problem and maybe someone here has an idea how to get me on the right path.

I have a file with the following...

Code:
[GRAY_CATS]
sometext, 123, 345, 678

****
[BROWN_DOGS]

sometext, 000, 111, 222
****
[RED_FOXES]

sometext, 333, 444, 555

****
I want to pull out the "000" in the BROWN_DOGS section. I have a sed expression that triggers on the 3 digits after "sometext, " and it works great. However, it pulls from all sections, not just the BROWN_DOGS section (as it should).

I'm looking to trigger on the "sometext, " that is only between the "[BROWN_DOGS]" and "****" which are guaranteed to be there. The number of lines and text before "sometext, " is them is not guaranteed, nor is the number of lines after.


Does anyone have any suggestions how to do this or at least a point in the right direction? I'm not sure how to handle the multiple lines.

Thank you folks for your time.
 
Old 09-28-2020, 09:44 AM   #2
pan64
LQ Guru
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 15,606

Rep: Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119
that looks like the "usual" ini files. sed is not really good at parsing such files, but you can use addressing:
Code:
sed '/GRAY/,/BROWN/<some command>'
 
Old 09-28-2020, 10:01 AM   #3
boughtonp
Member
 
Registered: Feb 2007
Location: UK
Distribution: Debian
Posts: 789

Rep: Reputation: 561Reputation: 561Reputation: 561Reputation: 561Reputation: 561Reputation: 561
Quote:
Originally Posted by luw View Post
I want to pull out the "000" in the BROWN_DOGS section. I have a sed expression that triggers on the 3 digits after "sometext, " and it works great. However, it pulls from all sections, not just the BROWN_DOGS section (as it should).
So what is your partially working sed command?

Because from that description it's unclear what you are trying to extract and in what situations? (somehow didn't see rest of the post earlier)

Do you actually need to use sed for this or are you open to more appropriate tools?


Last edited by boughtonp; 09-28-2020 at 01:10 PM.
 
Old 09-28-2020, 12:59 PM   #4
tofino_surfer
Member
 
Registered: Aug 2007
Posts: 440

Rep: Reputation: 130Reputation: 130
Quote:
I want to pull out the "000" in the BROWN_DOGS section. I have a sed expression that triggers on the 3 digits after "sometext, " and it works great. However, it pulls from all sections, not just the BROWN_DOGS section (as it should).

I'm looking to trigger on the "sometext, " that is only between the "[BROWN_DOGS]" and "****" which are guaranteed to be there. The number of lines and text before "sometext, " is them is not guaranteed, nor is the number of lines after.
For something this complex you should not use sed. You would need awk, perl, or python. You would need to set a flag when "[BROWN_DOGS]" is encountered which is reset when "****" is encountered. Then you would use this flag for conditional execution of the "sometext" pattern match. With perl you would need a loop with at least three pattern matches. With awk you would need at least three rules, one to set the flag, one to reset the flag, and one to perform a conditional match only when the flag is set.
 
Old 09-28-2020, 01:04 PM   #5
Turbocapitalist
LQ Guru
 
Registered: Apr 2005
Distribution: Linux Mint, Devuan, OpenBSD
Posts: 5,235
Blog Entries: 3

Rep: Reputation: 2587Reputation: 2587Reputation: 2587Reputation: 2587Reputation: 2587Reputation: 2587Reputation: 2587Reputation: 2587Reputation: 2587Reputation: 2587Reputation: 2587
Indeed. This is a job for perl. It's rather easy to read .ini configuration files in perl using the Config::Tiny or Config::IniFiles modules from CPAN.
 
Old 09-28-2020, 01:29 PM   #6
pan64
LQ Guru
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 15,606

Rep: Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119
Quote:
Originally Posted by Turbocapitalist View Post
Indeed. This is a job for perl. It's rather easy to read .ini configuration files in perl using the Config::Tiny or Config::IniFiles modules from CPAN.
Yes, you can do it easily in perl/python/java/awk/whatever, but actually there is an ini file parser in bash too (and there are more, not only this one).
 
Old 09-28-2020, 10:14 PM   #7
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 19,243

Rep: Reputation: 3382Reputation: 3382Reputation: 3382Reputation: 3382Reputation: 3382Reputation: 3382Reputation: 3382Reputation: 3382Reputation: 3382Reputation: 3382Reputation: 3382
Using an address range as suggested earlier it's pretty easy in sed in this case if the data are that well defined. You'll have to escape the asters if you use that as a bounding address.
 
Old 09-29-2020, 01:11 AM   #8
luw
LQ Newbie
 
Registered: Jan 2007
Location: greater nyc area
Distribution: ubuntu10 LTS, opensolaris 5.11, tinycore 3.x
Posts: 19

Original Poster
Rep: Reputation: 0
Thank you everyone.

My main motivation for using sed is strictly portability and not having to worry about perl or python etc being installed. However the consensus seems to be that it should be using something else.

I just tried playing with the perl example and I don't have the Config:Tiny.pm on my desktop and doubt my parents server (where this is destined) I'm afraid I would have the same issues with python; either needing the correct version or some library that wont be available.

boughtonp, because you asked, here is the sed line I currently have that works on all sections.
Code:
sed -i "s/\sometext, \(.\{3\}\)/sometext, $SOMEVAR/" filename.txt
I am open to other tools, just not sure where to start with another tool and concerned with portability. Awk probably has the best chance for being on my computers, but I have used it very little.

pan64, syg00,
I'm interested in 'addressing' method, though not familiar. Would this be something I could "tack on" before and/or after the above sed line?

Thank you again folks for taking the time to respond.
 
Old 09-29-2020, 02:13 AM   #9
pan64
LQ Guru
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 15,606

Rep: Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119Reputation: 5119
this is the official documentation of the gnu version of sed (about the usage of address): https://www.gnu.org/software/sed/man...Addresses.html It is not really user friendly.
this is much easier: https://docstore.mik.ua/orelly/unix/upt/ch34_04.htm
this is another one: https://www.thegeekstuff.com/2009/09...-and-patterns/
And also you can look for another tutorial/examples if you wish.
 
Old 09-29-2020, 02:32 AM   #10
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 19,243

Rep: Reputation: 3382Reputation: 3382Reputation: 3382Reputation: 3382Reputation: 3382Reputation: 3382Reputation: 3382Reputation: 3382Reputation: 3382Reputation: 3382Reputation: 3382
Quote:
Originally Posted by luw View Post
I'm looking to trigger on the "sometext, " that is only between the "[BROWN_DOGS]" and "****" which are guaranteed to be there.
So you already know what range of lines - in this context "address" doesn't have to be a number, it can be a regex. Simply put the range before your command (inside the double quotes). See post #2.

Last edited by syg00; 09-29-2020 at 02:34 AM. Reason: double quotes, not single in this case
 
Old 09-29-2020, 07:50 AM   #11
boughtonp
Member
 
Registered: Feb 2007
Location: UK
Distribution: Debian
Posts: 789

Rep: Reputation: 561Reputation: 561Reputation: 561Reputation: 561Reputation: 561Reputation: 561

As per above, addressing makes this easily solvable with Sed, and I'm not sure there will be a more portable and concise way of expressing it. (Though it still might be sensible to use/build a specific parser for the format.)

Regarding your pattern, you don't want that backslash before "sometext", and ".\{3\}" is less readable than "..." or "[^,]*" and you don't need to put a group around text you're throwing away - but you can avoid repeating the prefix with one.

Also, I prefer to avoid double quotes with sed - you can do so and still insert variables with the syntax 'command_start'"$VARIABLE"'commend_end'

In summary, I'd write that pattern this way:
Code:
sed -r 's/(sometext, )[^,]*/\1'"$SOMEVAR"'/'
After confirming it works, I'd then prefix with the addressing and double-check it only changes the relevant section, and only then would I maybe add the -i flag for in-place editing.

 
Old 09-29-2020, 08:02 AM   #12
lvm_
Member
 
Registered: Jul 2020
Posts: 48

Rep: Reputation: Disabled
Unless you like solving unnecessarily complicated puzzles, use awk - the right tool for the job, and you needn't worry about portability - core system packages depend on it, it is always present.

/^\[BROWN_DOGS\$]/ {scan=1;next}
/^\*\*\*$/ {scan=0;next}
{if(scan){do your stuff here}}
 
Old 09-30-2020, 02:52 PM   #13
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 1,524

Rep: Reputation: 690Reputation: 690Reputation: 690Reputation: 690Reputation: 690Reputation: 690
Try the following sed solution:
Code:
sed "
  /^\[BROWN_DOGS\]/,/^\*\*\*\*/ !b
  /sometext/ s/[0-9]\{1,\}/$SOMEVAR/1
" filename.txt
Whenever it is not in the given range, it branches(=jumps) to the end (where a default-print occurs before the next input cycle starts).
If it's within the range, do the substitution.
A smart way is to first search for the" sometext" then replace just the number; by default or with /1 it is the first number, with /2 it would be the 2nd number,...
 
Old 10-31-2020, 07:40 AM   #14
Georgian_B
LQ Newbie
 
Registered: Oct 2020
Posts: 1

Rep: Reputation: Disabled
I was looking for the information regarding the same.
 
  


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] jhalfs sed: -e expression #1, char 55:Invalid preceding regular expression percy_vere_uk Linux From Scratch 10 07-22-2017 08:15 AM
[SOLVED] sed gives :sed: -e expression #1, char 1: unknown command: `'' samasat Linux - Newbie 10 06-09-2012 06:31 PM
Bash script using sed - how to pick something out of a file? gankoji Slackware 4 08-07-2009 07:15 PM
sed extract parameters between sections freeindy Programming 5 07-19-2009 01:51 PM
Remove sections of a xml file with sed viniciusandre Linux - Software 2 04-20-2009 02:18 PM

LinuxQuestions.org > Forums > Linux Forums > Linux - Server

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