如何将带有空格的 \jobname 传递给外部 shell 命令

如何将带有空格的 \jobname 传递给外部 shell 命令

我需要传递\jobname给某个外部 shell 命令并使用语法读回其输入\input{|"<shell command>"}。但是\jobname可能包含空格。那么如何为 shell 引用它?

% pdflatex --shell-escape "file with spaces"
\documentclass[]{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\begin{document}
  \input{|"wc \jobname"} % how to quote \jobname here?
\end{document}

答案1

通常\jobname设置为主输入文件名;但是,当文件中有空格时,pdftex会在 中添加(双)引号\jobname

因此,为了开展业务,您必须删除这些引号。以下是\unquotedjobname在序言中定义新宏的一种方法:

\documentclass{article}

\def\uqji#1#2\relax{%
  \ifx"#1%
    \uqjii#2%
  \else
    \let\unquotedjobname\jobname
  \fi}
\def\uqjii#1"{\def\unquotedjobname{#1}}
\expandafter\uqji\jobname\relax

\begin{document}

\input{"|wc '\unquotedjobname.tex'"}

\end{document}

请注意,您必须提供.tex扩展名,否则引用会错误。


以下是此问题的一个可能的完整解决方案;请注意,XeTeX 还接受"名称中包含的文件名,在这种情况下,它会\jobname用单引号括起来。在这种情况下,您可能无法使用文件名,除非您进行其他翻筋斗,所以这个问题并不那么重要。

\documentclass{article}
\usepackage{ifxetex,ifluatex}
\ifxetex
  \usepackage{fontspec}
\else
  \ifluatex
    \usepackage{fontspec}
  \else
    \usepackage[T1]{fontenc}
    \usepackage[utf8]{inputenc}
  \fi
\fi

\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\fixjobname}{sO{\xjobname}}
 {
  \IfBooleanTF{#1}
   { \fixjobname_print:N #2 }
   { \fixjobname_string:N #2 }
 }
\tl_new:N \l_fixjobname_temp_tl
\cs_new_protected:Npn \fixjobname_print:N #1
 {
  \fixjobname_unquote:
  \tl_set_rescan:NnV #1 { } \l_fixjobname_temp_tl
 }
\cs_new_protected:Npn \fixjobname_string:N #1
 {
  \fixjobname_unquote:
  \tl_set_eq:NN #1 \l_fixjobname_temp_tl
 }

%%% Uncomment this if you don't want to use l3regex
%\cs_new_protected:Npn \fixjobname_unquote:
% {
%  \tl_set_eq:NN \l_fixjobname_temp_tl \c_sys_jobname_str
%  \str_case_e:nnF { \tl_head:N \l_fixjobname_temp_tl }
%   {
%    { " } { \fixjobname_trim: } % double quoted jobname
%    { ' } { \fixjobname_trim: } % single quoted jobname (XeTeX)
%   }
%   { } % do nothing
% }
%\cs_new:Npn \fixjobname_trim:
% {
%  \tl_set:Nx \l_fixjobname_temp_tl { \tl_tail:N \l_fixjobname_temp_tl }
%  \tl_set:Nx \l_fixjobname_temp_tl { \tl_reverse:V \l_fixjobname_temp_tl }
%  \tl_set:Nx \l_fixjobname_temp_tl { \tl_tail:N \l_fixjobname_temp_tl }
%  \tl_set:Nx \l_fixjobname_temp_tl { \tl_reverse:V \l_fixjobname_temp_tl }
% }
%%% This works with l3regex
\cs_new_protected:Npn \fixjobname_unquote:
 {
  \tl_set_eq:NN \l_fixjobname_temp_tl \c_sys_jobname_str
  \regex_replace_all:nnN { \A ("|') ( .* ) ("|') \Z } { \2 } \l_fixjobname_temp_tl
 }
%%% End of l3regex dependent part
\cs_generate_variant:Nn \tl_set_rescan:Nnn { NnV }
\ExplSyntaxOff


\begin{document}
\fixjobname \xjobname \ (string)

\fixjobname*[\foo] \foo \ (UTF8)

\end{document}

\fixjobname定义\xjobname为一个字符串,它应该可以将其传递给 shell(但是,根据所使用的文件系统,通信可能不太好)。你可以说

\fixjobname*

通过重新扫描字符串来定义\xjobname,这对于打印很有用。如果使用 XeLaTeX 或 LuaLaTeX,则没有区别。您仍然可以添加一个可选参数,这将是定义为保存结果的序列,而不是\xjobname

有两个版本:最有效的一个使用l3regex;如果你不想处于边缘,只需取消注释前面的部分并注释掉请求l3regex和相应的代码。

答案2

引用取决于 shell,但这是 cygwin bash:

在此处输入图片描述

% pdflatex --shell-escape "file with spaces"
\documentclass[]{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\def\requote"#1"{'#1.tex'}

\typeout{Xwc \expandafter\requote\jobname X}
\begin{document}
  \input{|"wc \expandafter\requote\jobname"} % how to quote \jobname here?
\end{document}

以上需要空格,因此\jobname被引用。如果您还需要处理不带空格的文件名,则需要先检查是否有空格,"然后再将其替换为'

% pdflatex --shell-escape "file with spaces"
\documentclass[]{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}


\def\requote#1{\ifx"#1\expandafter\xrequote\else\expandafter\yrequote\fi#1}
\def\xrequote"#1"\relax{'#1.tex'}
\def\yrequote#1\relax{#1.tex}


\begin{document}
  \input{|"wc \expandafter\requote\jobname\relax"} % how to quote \jobname here?
\end{document}

相关内容