Cuaderno de GNUtas

Incluir parte de un documento LaTeX en otro

Siempre es buena práctica en LATEX incluir las secciones y capítulos de un documento como ficheros externos. Trabajar de esta forma con un documento maestro resulta más cómodo a la hora de controlar y depurar el código, además de que podemos compilar sólo partes del documento a voluntad. Pero, a diferencia del comando en línea de Org Mode #+INCLUDE:, la macro \input de LATEX no permite incluir sólo partes de un documento. Por ejemplo desde la línea tal a la línea cual. Hay una serie de escenarios donde este requerimiento podría tener sentido, como en caso de que queramos reutilizar un preámbulo de otro documento. O incluir otro documento sin su preámbulo. En todo caso, ya que la carencia es importante y me hacía falta contar con una funcionalidad así, se me ocurrió escribir esta serie de macros que vienen a hacernos el apaño. Todas comparten las siguientes características:

  1. Generan un script durante la compilación
  2. Ejecutan el comando de bash sed, que es en realidad el que hace el trabajo
  3. Crean un documento en el mismo directorio con el texto a incluir

Como puede verse, no es una solución del todo limpia, pues produce archivos nuevos en el directorio de trabajo; ni es una solución cien por cien LATEX, al echar mano de un comando de bash. Pero, bueno, es lo que hay y funcionar, funciona. Pasemos, pues, a describir estas macros, que por comodidad las definimos mediante el paquete xparse. Empezamos, por tanto, cargando dicho paquete:

\usepackage{xparse}

Y como nos hará falta definir antes una pequeña función en Lua, también cargamos luacode:

\usepackage{luacode}

Y, acto continuo, definimos la función, que se encargará de hacer ejecutable y ejecutar el script generado en la compilación, y de añadir la macro \input con el texto a incluir:

\begin{luacode}

      function mi_input (y)
      local x = io.popen([[chmod +x extraer_doc.sh && ./extraer_doc.sh]])
      local y = "\\input{temp.tex}"
      tex.print (y)
      x:close ()
      end

\end{luacode}

Nuestra primera macro definida con xparse admite tres argumentos obligatorios: línea desde, línea hasta y fichero a incluir. Y como argumentos opcionales: término a sustituir en temp.tex (vale usar también expresiones regulares) y término con que sustituir. Por ejemplo, si de un fichero que queremos incluir, llamado mifichero.tex, queremos cargar de la línea 10 a la 20, y que se sustituya en lo que cargamos cualquier ocurrencia de la cadena «Juan Gómez» por la cadena «Sr. Gómez», pondríamos en nuestro documento: \MiInput{10}{20}{mifichero.tex}[Juan Gómez][Sr. Gómez]:

\DeclareDocumentCommand\MiInput{ m m m o o }{%
      \newwrite\script
      \immediate\openout\script=extraer_doc.sh
      \immediate\write\script{\string##!/bin/bash}
      \immediate\write\script{sed -ne #1,#2p #3 > temp.tex;}
      \IfNoValueF {#4#5} {\immediate\write\script{sed -i 's/#4/#5/g' temp.tex}}
      \immediate\write\script{exit}%
      \immediate\closeout\script%
       {\directlua{mi_input()}}}

Esta variante admite un sólo argumento opcional para añadir lo que se quiera al script (por ejemplo, múltiples reemplazos sobre el archivo temp.tex usando el comando sed, etc.)

\DeclareDocumentCommand\MiInputvar{ m m m o }{%
       \newwrite\script
      \immediate\openout\script=extraer_doc.sh
      \immediate\write\script{\string##!/bin/bash}
      \immediate\write\script{sed -ne #1,#2p #3 > temp.tex;}
      \IfNoValueF {#4} {\immediate\write\script{#4}}
    \immediate\write\script{exit}%
    \immediate\closeout\script%
    {\directlua{mi_input()}}}

Y esta tercera y última variante nos cargará un documento, pero sólo la parte que se encuentre entre el \begin{document} y el \end{document}. Útil, por ejemplo, para reutilizar otro documento de LATEX. Admite un único argumento obligatorio, que es el documento a incluir:

\DeclareDocumentCommand\MiInputContenido{ m }{%
    \newwrite\script
    \immediate\openout\script=extraer_doc.sh
    \immediate\write\script{\string##!/bin/bash}
    \immediate\write\script{sed -n '/^\\begin{document}/,/^\\end{document}/p' #1 > temp.tex}
      \immediate\write\script{sed -i 's/\\begin{document}\|\\end{document}//g' temp.tex}
     \immediate\write\script{exit}%
    \immediate\closeout\script%
     {\directlua{mi_input()}}}

La compilación ha de ser con LuaLATEX desde la terminal, añadiendo la opción -shell-escape.

Publicado: 29/06/20

Última actualización: 21/01/22


Índice general

Acerca de...

Esta obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial 4.0 Internacional.

© Juan Manuel Macías
Creado con esmero en
GNU Emacs