1

my file looks like this

//
[297]((((21:0.125204,20:0.125204):0.00994299,(28:0.0790047,(7:0.0146105,5:0.0146105):0.0643943):0.0561423):0
segsites:
positions: 1 2 4 6 9 10 45 67 78 89 
01010101010101010101010101011111010101

I would need to parse it into three different files

//
[297]((((21:0.125204,20:0.125204):0.00994299,(28:0.0790047,(7:0.0146105,5:0.0146105):0.0643943):0.0561423):0

then

 segsites:
    positions: 1 2 4 6 9 10 45 67 78 89 

an

 01010101010101010101010101011111010101

the problem is that there are not a fixed number of lines starting with the brackets and so on. the final line could start with either a 0 or an 1 and that is a problem as I dont know how to tell grep to search for either 0 or 1. I would need to grep for the []. then the segsites and the line below which includes the pos and then the numeric line with 01

5
  • 1. Is the line with brackets always followed by a segsites line? 2. Is segsites always followed by a single positions line? And is positions always followed by a single line of zeroes and ones? To grep for zeros or ones: grep '^[01]*$'.
    – muru
    Apr 26, 2015 at 12:11
  • for 1-2 yes...but it could be n lines all starting with [] and. Positions is followed by an hunknown number of 0 and 1 which can all start either with 0 or with 1 Apr 26, 2015 at 12:15
  • But any lines containing only 0s and 1s will be going to the third file? And any lines which contain segsites or positions go to the second file? And all other lines go to the first line?
    – muru
    Apr 26, 2015 at 12:18
  • yes that is the way it shoudl be Apr 26, 2015 at 12:19
  • 1
    Please stop vandalising. There is nothing wrong with your posts.
    – Tim
    May 21, 2015 at 20:09

2 Answers 2

3

Well, in awk:

awk '/^[01]+$/ {print > "third-file"; next} 
 /(segsites|positions)/ {print > "second-file"; next} 
 {print > "first-file"}' input-file

Considering three cases:

  • A line containing only 0s and 1s (/^[01]+$/)
  • A line containing either segsites or positions: /(segsites|positions)/
  • All other lines

In each case, we print to different file and proceed to the next line. Change "third-file", "second-file", "first-file" to appropriate names (keep the quotes).

1

Using grep with PCRE [-P] and Dotall modifier [(?s)]:

1st portion:

$ grep -Poz "(?s)^.*?(?=\nsegsites:)" file.txt 
//
[297]((((21:0.125204,20:0.125204):0.00994299,(28:0.0790047,(7:0.0146105,5:0.0146105):0.0643943):0.0561423):0

2nd portion:

$ grep -Poz "(?s)segsites.*?(?=\n[10]+$)" file.txt 
segsites:
positions: 1 2 4 6 9 10 45 67 78 89 

In case of third portion only grep will do (if you have just one line):

$ grep -E "^[01]+$" file.txt
01010101010101010101010101011111010101

If you are not sure (single/multiple lines):

$ grep -Poz "(?<=\n)(?:[10]|\n)*(?=\n$)" file.txt 
010101010101010101010101010111110101011
01010101010101010101010101011111010101010

$ grep -Poz "(?<=\n)(?:[10]|\n)*(?=\n$)" file.txt 
010101010101010101010101010111110101011

Explanations:

  • grep -P represents PCRE (Perl Compatible Regular Expressions)

  • grep -o will select only the matched portion

  • grep -z will cause lines to be separated by ASCII NUL instead of new lines

  • (?s) is called Dotall modifier, using this any character (including line breaks) can be matched by .

  • (?=) is Positive lookahead, represents what follows our match

  • (?<) is Positive lookbehind, represents what precedes our match

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .