% \iffalse meta-comment % (The MIT License) % % Copyright (c) 2021-2022 Yegor Bugayenko % % Permission is hereby granted, free of charge, to any person obtaining a copy % of this software and associated documentation files (the 'Software'), to deal % in the Software without restriction, including without limitation the rights % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell % copies of the Software, and to permit persons to whom the Software is % furnished to do so, subject to the following conditions: % % The above copyright notice and this permission notice shall be included in all % copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE % SOFTWARE. % \fi % \CheckSum{0} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % \GetFileInfo{iexec.dtx} % \DoNotIndex{\endgroup,\begingroup,\let,\else,\fi,\newcommand,\newenvironment} % \iffalse %<*driver> \ProvidesFile{iexec.dtx} % %\NeedsTeXFormat{LaTeX2e} %\ProvidesPackage{iexec} %<*package> [2022-10-12 0.9.0 Inputable Shell Executions] % %<*driver> \documentclass{ltxdoc} \usepackage[tt=false, type1=true]{libertine} \usepackage{microtype} \usepackage{iexec} \usepackage{href-ul} \PageIndex \EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} \DocInput{iexec.dtx} \PrintChanges \PrintIndex \end{document} % % \fi % \title{|iexec|: \LaTeX{} Package \\ for Inputable Shell Executions\thanks{The sources are in GitHub at \href{https://github.com/yegor256/iexec}{yegor256/iexec}}} % \author{Yegor Bugayenko \\ \texttt{yegor256@gmail.com}} % \date{\filedate, \fileversion} % % \maketitle % % \section{Introduction} % % This package helps you execute shell commands right from the % document and then put their output to the document: % % \begin{multicols}{2} % \setlength{\parskip}{0pt} % \small % \raggedcolumns %\iffalse %<*verb> %\fi \begin{verbatim} \documentclass{article} \usepackage{iexec} \begin{document} Today is \iexec{date +\%e-\%b-\%Y} \end{document} \end{verbatim} %\iffalse % %\fi % % \columnbreak % % Today is \iexec[log]{date +\%e-\%b-\%Y} % \end{multicols} % \DescribeMacro{\iexec} % The only command provided by this package is |\iexec| \oarg{options} \marg{cmd}. % Its only mandatory argument \meta{cmd} is the command to be executed % through the terminal shell (bash, or whatever is set as the default one % on your user console). % You have to run |pdflatex| (or just |latex|) % with the |--shell-escape| flag % in order to let |shellesc| (the package we use) % to execute your shell command. % \section{Options} % \DescribeMacro{quiet} % If you don't want the output to be visible, % use |\phantom\{\iexec{...}}|. % Otherwise, you can use |quiet| option: %\iffalse %<*verb> %\fi \begin{verbatim} \documentclass{article} \usepackage{iexec} \begin{document} I just want to delete some file: \iexec[quiet]{rm -f foo.txt} \end{document} \end{verbatim} %\iffalse % %\fi % In this case, whatever the shell command produces will not be included % into the document. % \DescribeMacro{stdout} % The output of your code is saved into the file provided as an % optional argument of |\iexec| (the default value is |iexec.tmp|): %\iffalse %<*verb> %\fi \begin{verbatim} \documentclass{article} \usepackage{iexec} \begin{document} Today is \iexec[stdout=date.txt]{date +\%e-\%b-\%Y | tr -d '\\n'}. \end{document} \end{verbatim} %\iffalse % %\fi % The tailing part of the command here removes all ends-of-line. % \DescribeMacro{stderr} % The error output of the code is saved into the file provided as an % optional argument of |\iexec| (by default the error output % is streamed into |stdout|): %\iffalse %<*verb> %\fi \begin{verbatim} \documentclass{article} \usepackage{iexec} \begin{document} Today is \iexec[stderr=my.txt]{broken-command}. \end{document} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{trace} % The file specified will be deleted right after its usage. If you don't % want this to happen, use |trace| package option: all files will remain % in the directory where they were created. % It's possible to turn tracing on globbaly, for the entire document, using % |trace| option of the package: %\iffalse %<*verb> %\fi \begin{verbatim} \documentclass{article} \usepackage[trace]{iexec} \begin{document} This file won't be deleted: \iexec[stdout=me.txt]{whoami}. \end{document} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{append} % The stdout produced will be appended to the file specified: %\iffalse %<*verb> %\fi \begin{verbatim} \documentclass{article} \usepackage[trace]{iexec} \begin{document} \iexec[append,stdout=foo.txt,quiet]{echo 'Hello, '} \iexec[append,stdout=foo.txt,quiet]{echo 'Jeffrey!'} \input{foo.txt} \end{document} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{log} % The stdout produced will be printed in \TeX{} log: %\iffalse %<*verb> %\fi \begin{verbatim} \documentclass{article} \usepackage{iexec} \begin{document} \iexec[log]{echo 'Hello, \\LaTeX!'} \end{document} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{null} % The stdout of the command will be sent to |/dev/null|: %\iffalse %<*verb> %\fi \begin{verbatim} \documentclass{article} \usepackage{iexec} \begin{document} \iexec[null]{rm some-file.txt} \end{document} \end{verbatim} %\iffalse % %\fi % \StopEventually{} % \section{Implementation} % \changes{v0.2.0}{2021/07/10}{Initial version} % \changes{v0.4.0}{2021/08/01}{Runtime verification for --shell-escape option} % \changes{v0.4.1}{2021/08/08}{Options trace, stdout, and quiet added} % \changes{v0.5.0}{2022/01/08}{Major bug fixes} % \changes{v0.6.0}{2022/10/09}{Additional options 'log' and 'append'} % \changes{v0.7.0}{2022/10/10}{Additional option 'null'} % \changes{v0.8.0}{2022/10/11}{Bug fixes} % \changes{v0.9.0}{2022/10/12}{Additional option 'stderr'} % First, we include a few packages: % \begin{macrocode} \RequirePackage{shellesc} \RequirePackage{pgfkeys} \RequirePackage{expl3} % \end{macrocode} % Then, we parse package options: % \begin{macrocode} \RequirePackage{xkeyval} \makeatletter\newif\ifiexec@trace \DeclareOptionX{trace}{\iexec@tracetrue} \ProcessOptionsX\relax\makeatother \makeatletter\pgfkeys{ /iexec/.is family, /iexec, stdout/.estore in = \iexec@stdout, stdout/.default = iexec.tmp, stderr/.estore in = \iexec@stderr, trace/.estore in = \iexec@traceit, append/.estore in = \iexec@append, log/.estore in = \iexec@log, null/.estore in = \iexec@null, quiet/.estore in = \iexec@quiet, stdout }\makeatother % \end{macrocode} % \begin{macro}{\iexec@typeout} % Then, we define an internal command |\iexec@typeout| for printing the content of a file, % as suggested \href{https://tex.stackexchange.com/questions/660808}{here}: % \begin{macrocode} \makeatletter\ExplSyntaxOn \NewDocumentCommand{\iexec@typeout}{m}{ \iexec_typeout_file:n { #1 }} \ior_new:N \g_iexec_typeout_ior \cs_new_protected:Nn \iexec_typeout_file:n { \ior_open:Nn \g_iexec_typeout_ior { #1 } \ior_str_map_inline:Nn \g_iexec_typeout_ior {\iow_term:n { ##1 }} \ior_close:N \g_iexec_typeout_ior } \ExplSyntaxOff\makeatother % \end{macrocode} % \end{macro} % \begin{macro}{\iexec} % Then, we define |\iexec| command. % It is implemented with the help of |\ShellEscape| from |shellesc| package: % \begin{macrocode} \makeatletter\newcommand\iexec[2][]{% \begingroup \pgfqkeys{/iexec}{#1}% % \end{macrocode} % First, we verify that |latex| is running with |--shell-escape| option, since without % it nothing will work; so, it's better to throw an error earlier than later: % \begin{macrocode} \ifdefined\pdfshellescape\ifnum\pdfshellescape=1\else% \PackageError{iexec}{You must run TeX processor with --shell-escape option}{}% \fi\fi% \begingroup% % \end{macrocode} % Then, start the log from a clean line: % \begin{macrocode} \message{^^J}% % \end{macrocode} % Then, we define a few special chars in order to escape them in the shell % (the full % list of them is in \href{https://ctan.mirror.norbert-ruehl.de/info/macros2e/macros2e.pdf}{macros2e}): % \begin{macrocode} \let\%\@percentchar% \let\\\@backslashchar% \let\{\@charlb% \let\}\@charrb% % \end{macrocode} % Then, we execute it: % \begin{macrocode} \def\iexec@cmd{(#2) \ifdefined\iexec@append>\fi> \ifdefined\iexec@null/dev/null\else\iexec@stdout\fi \space\ifdefined\iexec@stderr2>\iexec@stderr\else2>&1\fi} \ShellEscape{\iexec@cmd}% % \end{macrocode} % Then, a message is printed to TeX log: % \begin{macrocode} \message{iexec: [\iexec@cmd]^^J}% \endgroup% % \end{macrocode} % Then, if required, the content of the stdout file will be printed to the log: % \begin{macrocode} \ifdefined\iexec@null\else \ifdefined\iexec@log \message{iexec: this is the content of \iexec@stdout:^^J}% \iexec@typeout{\iexec@stdout} \message{^^J}% \fi\fi% % \end{macrocode} % Then, include the produced output into the current document: % \begin{macrocode} \ifdefined\iexec@null\else \ifdefined\iexec@quiet \message{iexec: Due to 'quiet' option we didn't read the content of '\iexec@stdout' (\pdffilesize{} bytes)^^J}% \else% \message{iexec: We include the content of '\iexec@stdout' (\pdffilesize{} bytes)...^^J}% \input{\iexec@stdout}% \message{iexec: The content of '\iexec@stdout' was included into the document^^J}% \fi\fi% % \end{macrocode} % Finally, delete the file or leave it untouched: % \begin{macrocode} \ifdefined\iexec@null\else \ifiexec@trace% \message{iexec: Due to package option 'trace', the file '\iexec@stdout' was not deleted^^J}% \else% \ifdefined\iexec@traceit% \message{iexec: Due to 'trace' option, the file '\iexec@stdout' was not deleted^^J}% \else% \ShellEscape{rm \iexec@stdout}% \message{iexec: The file '\iexec@stdout' was deleted^^J}% \fi% \fi\fi% \endgroup }\makeatother % \end{macrocode} % \end{macro} % \Finale %\clearpage % %\PrintChanges %\clearpage %\PrintIndex