How to pass \jobname with whitespace to external shell command

Usually \jobname is set to the main input file name; however, when the file has spaces in it, pdftex adds (double) quotes around it in \jobname.

So, for doing your business you have to strip off those quotes. Here's a way that defines a new macro \unquotedjobname in the preamble:

\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}

Notice that you have to supply the .tex extension or the quoting would be wrong.


Here is a possible complete solution to this problem; note that XeTeX accepts also file names that contain " in their name and in this case it quotes \jobname with single quotes. You won't probably be able to use the filename in this case without some other somersault, so the problem is not so important.

\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}

The macro \fixjobname defines \xjobname as a string, which should work for passing it to the shell (however the communication might not be so good depending on the file system used). You can say

\fixjobname*

to define \xjobname by rescanning the string, useful for printing. In case XeLaTeX or LuaLaTeX are used there's no difference. You can still add an optional argument and that will be the sequence defined to hold the result instead of \xjobname.

There are two versions: the most efficient one uses l3regex; if you don't want to live on the edge, just uncomment the previous part and comment out the request for l3regex and the corresponding code.


Quoting depends on the shell, but this is cygwin bash:

enter image description here

% 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}

The above requires a space so that \jobname is quoted. If you also need to work with filenames without spaces you need to check for a " before replacing it by '

% 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}

Tags:

Jobname