# Extracting pattern from multiple lines

I have a file test.tex with content that is similar to this:

\documentclass{scrartcl}
\usepackage{graphicx}
\title{Test}
\author{Author 1, Author 2, Author 3}
\begin{document}
\end{document}


I want to extract every author that is written in the { ... }. Therefore I did the following:

authors=$(cat test.tex | grep '\author' | tr -d '\author' | tr -d '{' | tr -d '}' )  This code works only for this case. My problem is that 1. there could be [] instead of {} 2. the line could span over multiple lines like the following example \author{Author 1, Author 2, Author 3} Does anyone know how to solve these two problems? ## 4 Answers #!/bin/bash sed -nr ' /\\author/ { :ending /]|}$/! {
N
b ending
}
s/\\author(\{|\[)(.*)(}|])/\2/p
}
' test.tex


#!/bin/bash

sed -nr '
# if the line contains the \author string, we are working with it.
/\\author/ {

##### this part are needed for multiple line pattern processing

# put a label here. We will be return to this point,
# until we reach line, which have } or ] in the ending.
:ending

# if this line does not ended by } or ].
# It is tell us, that this line continues on the next line.
/]|}$/! { # Take the next line and append it to the previous line. # Just join them together. N # Go to the ":ending" label b ending } ##### ending multiple line pattern processing # remove the \author word and brackets from line s/\\author(\{|\[)(.*)(}|])/\2/p } ' test.tex  test.tex \documentclass{scrartcl} \usepackage{graphicx} \title{Test} \author{Author 1, Author 2, Author 3} \author[Author 1, Author 2, Author 3] \author{Author 1, Author 2, Author 3} \author[Author 1, Author 2, Author 3] \begin{document} \end{document}  output Author 1, Author 2, Author 3 Author 1, Author 2, Author 3 Author 1, Author 2, Author 3 Author 1, Author 2, Author 3  • Thanks! It worked and... I learned quite few from the explanation^^ – ADDB Jul 15 '17 at 20:04 grep -zPo '\\author{\K[^}]*' ex1.tex | tr '\0\n' '\n '  Some quick explanation notes: • -z input and output records ("lines") are separated by NULL (\0). So the full TeX file will be one single record. • -P Use Perl pcre regular expression variant. • -o output just the part of the record that matches the regExp. • \\author{\K means left context The tr '\0\n' '\n ' changes the output record separator (\0 to \n) and removes NewLines inside names (\n to ) • Would you mind explaining the command? – ADDB Jul 15 '17 at 16:06 This seems to do the job: egrep -o '[\[{]?Author' | sed -E 's/[\[{]//' ### Examples: 1) echo "\documentclass{scrartcl} \usepackage{graphicx} \title{Test} \author[Author 1, Author 2 Author 3 ] " | egrep -o '[\[{]?Author' | sed -E 's/[\[{]//' Author Author Author  2) echo "\documentclass{scrartcl} \usepackage{graphicx} \title{Test} \author[Author 1, Author 2, Author 3] \begin{document} \end{document}" | egrep -o '[\[{]?Author' | sed -E 's/[\[{]//' Author Author Author  3) echo "\documentclass{scrartcl} \usepackage{graphicx} \title{Test} \author{Author 1, Author 2, Author 3} \begin{document} \end{document}" | egrep -o '[\[{]?Author' | sed -E 's/[\[{]//' Author Author Author  You can probably do it using only grep and lookbehinds and whatnot. I personally have no problems using a pipe into sed after grep. • This is close but not exactly. The author 1, author 2... Were supposed to be placeholder for actual names. (e.g. Author 1 = Ryan Banana) if you could change it so that that works too I'll accept your answer. – ADDB Jul 15 '17 at 16:05 ### Python With your input file as given in the question, one liner can be done as so: $ python -c 'import sys,re;f=open(sys.argv[1],"r");a=tuple(l for l in f.readlines() if l.startswith("\\author") );print("\n".join(re.split(", |,|{|}",a[0].strip())[1:]))' input.tex
Author 1
Author 2
Author 3


And a script as so:

#!/usr/bin/env python

import sys,re

# read the doc, find the desired line
line=""
with open(sys.argv[1]) as f:
for l in f:
if l.startswith("\\author"):
line=l.strip()
break
# split at multiple separators, get slice of that list starting since 2nd item
author_list = re.split( ", |,|{|}", line )[1:]
# print 1 author per line
print("\n".join(author_list))


The key steps are two fold - read the file and find the line that stars with \\authors string, and then break the line at multiple separators into list of tokens, and build a new-line separated string out of that list of tokens. I also took the liberty to consider possibility that you may have to split either at , or ,<space>.