Script para extraer entradas seleccionadas de un archivo bibtex

11

Tengo un archivo bibtex grande con muchas entradas donde cada entrada tiene la estructura general

@ARTICLE{AuthorYear,
item = {...},
item = {...},
item = {...},
etc
}

(en algunos casos ARTICLEpodría ser una palabra diferente, por ejemplo BOOK)

Lo que me gustaría hacer es escribir un script simple (preferiblemente solo un script de shell) para extraer entradas con AuthorYear dado y ponerlas en un nuevo archivo .bib.

Me imagino que puedo reconocer la primera oración de una entrada por AuthorYear y la última por el cierre único }y tal vez usar sedpara extraer la entrada, pero realmente no sé cómo hacer esto exactamente. ¿Alguien puede decirme cómo lograría esto?

Probablemente debería ser algo como

sed -n "/AuthorYear/,/\}/p" file.bib

Pero eso se detiene debido al cierre }en el primer elemento de la entrada, dando así esta salida:

@ARTICLE{AuthorYear,
item = {...},

Por lo tanto, necesito reconocer si }es el único carácter en una línea y solo he dejado de leer cuando este es el caso.

Michiel
fuente
Sólo podía modificar el código un poco: sed -n "/AuthorYear/,/\}$/p". Tenga en cuenta el $símbolo. Funciona bien, excepto que no imprime el cierre }de un bibitem. Por cierto, ¿es sednecesario el uso de ?
Barun
@Barun el uso de sedno es necesario en absoluto, solo pensé que sería la opción más fácil. He descubierto un código ligeramente diferente: sed -n "/AuthorYear/, /^ *\}/p"que parece hacer exactamente lo que quiero, incluido el cierre }y la corrección de espacios si hay alguno
Michiel

Respuestas:

2

El siguiente script de Python realiza el filtrado deseado.

#!/usr/bin/python
import re

# Bibliography entries to retrieve
# Multiple pattern compilation from: http://stackoverflow.com/a/11693340/147021
pattern_strings = ['Author2010', 'Author2012',]
pattern_string = '|'.join(pattern_strings)
patterns = re.compile(pattern_string)


with open('bibliography.bib', 'r') as bib_file:
    keep_printing = False
    for line in bib_file:
        if patterns.findall(line):
            # Beginning of an entry
            keep_printing = True

        if line.strip() == '}':
            if keep_printing:
                print line
                # End of an entry -- should be the one which began earlier
                keep_printing = False

        if keep_printing:
            # The intermediate lines
            print line,

Personalmente, prefiero pasar a un lenguaje de secuencias de comandos cuando la lógica de filtrado se vuelve compleja. Eso, tal vez, tiene una ventaja en el factor de legibilidad al menos.

Barun
fuente
Cuidado, hay muchas entradas con {}s anidados . Si puede asegurarse de que la entrada termine con \n}, puede parar con^}
vonbrand
8

Recomendaría usar un lenguaje con una biblioteca BibTeX probada en batalla en lugar de reinventar esa rueda. Por ejemplo

#!/usr/bin/env perl
use strict;
use warnings;
use autodie;
use BibTeX::Parser;

open my $fh, '<', $ARGV[0];
my $parser = BibTeX::Parser->new($fh);
my @authoryear;
while (my $entry = $parser->next) {
    if ($entry->parse_ok) {
        if ($entry->key eq "AuthorYear") {
            push @authoryear, $entry;
        }
    }
    else {
        warn "Error parsing file: " . $entry->error;
    }
}

# I'm not familiar with bibtex files, so this may be insufficient
open my $out, '>', "authoryear.bib";
foreach my $entry (@authoryear) {
    say $out $entry->raw_bibtex;
}

Probablemente tendrá que instalar el módulo: cpan install BibTeX::Parser

Glenn Jackman
fuente
1

Ahora también tenemos el módulo bibparsing de Python, que permite analizar bases de datos BibTeX con Python. Por ejemplo, utilizo el siguiente script para calcular el número de autores en artículos de colaboración:

#!/usr/bin/python
import sys
import bibtexparser as bp
with open(sys.argv[1]) as bibtex_file:
    bd = bp.load(bibtex_file)
    for art in bd.entries_dict:
    print("*********")
    ae = bd.entries_dict[art]
    print(ae[u'title'])
    auths=ae[u'author'].split(" and ")
    print(len(auths))
    print(auths[0]+" --- "+auths[-1])
wzab
fuente
1

Otra opción sería usar bibtool.

Ejemplo:

bibtool -- select{$key AuthorYear”} input.bib -o output.bib

Consulte el manual para casos específicos.

Kirk Walla
fuente
0

Este es un script Bash que lee cada línea y utiliza la coincidencia de expresiones regulares para extraer cada entrada que tiene el patrón requerido en su cabeza. Puedes llamarlo getbibso algo así:

#!/usr/bin/env bash
# usage: ./getbibs pattern input.bib output.bib

while read entry; do
    if [[ $entry =~ ^@.*{$1,$ ]]; then
        printf "%s\n" "$entry" >> "$3"
        while read item; do
            [[ $item =~ ^@.*$ ]] && break
            printf "%s\n" "$item" >> "$3"
        done
    fi
done < "$2"

Para extraer todas las entradas con un año de autor de 1989, puede hacer:

$ chmod +x ./getbibs
$ ./getbibs 1989 file.bib author.bib

Puede tener algunos problemas que aún no he probado, pero parece funcionar bien para la tarea.


fuente
0

Para ser completos, la forma en que me di cuenta, no es tan agradable como algunos de los otros, pero funciona:

entries=( AuthorYear1 AuthorYear2 )
for entry in "${entries[@]}" do
     sed -n "/"${entry}"/, /^ *\}/p" refs.bib 
done

Se puede ejecutar desde la línea de comandos o poner en un script bash.

Michiel
fuente