3

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 4

4
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 )

1
  • Would you mind explaining the command?
    – ADDB
    Jul 15, 2017 at 16:06
2
#!/bin/bash

sed -nr '
/\\author/ {
    :ending
    /]|}$/! {
        N   
        b ending 
    }
    s/\\author(\{|\[)(.*)(}|])/\2/p
}
' test.tex

Explanation (code the same, but comments added):

#!/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
1
  • Thanks! It worked and... I learned quite few from the explanation^^
    – ADDB
    Jul 15, 2017 at 20:04
2

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.

1
  • 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, 2017 at 16:05
2

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>.

You must log in to answer this question.

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