There is \@percentchar
that expands to a literal %
character. You need to enclose your writing operation in a \makeatletter
\makeatother
pair
\makeatletter
\newwrite\outfile
\immediate\openout\outfile=example.dat
\immediate\write\outfile{\@percentchar}
\immediate\closeout\outfile
\makeatother
An alternative with escaping the %
inspired by an example where
git log -1 --pretty=format:"%h-%ad" --date=short > /tmp/temp.dat
needs to be passed to \write18
\makeatletter
\newcommand\dosystem{%
\@ifstar{\@tempswafalse\do@system}{\@tempswatrue\do@system}%
}
\newcommand\do@system[1]{%
\begingroup
\let\%\@percentchar
\if@tempswa\expandafter\immediate\fi
\write18{#1}%
\endgroup
}
\makeatother
so the command above can be executed by saying
\dosystem{git log -1 --pretty=format:"\%h-\%ad" --date=short > /tmp/temp.dat }
With \dosystem*
the \write
is delayed at the next shipout (because \immediate
is not executed).
Other characters can be escaped using the same idea, adding other \let
instructions. If also braces and #
are needed, an extended definition would be
\makeatletter
\newcommand\dosystem{%
\@ifstar{\@tempswafalse\do@system}{\@tempswatrue\do@system}%
}
\edef\@hashmark{\string#}\edef\@lbrace{\string{}\edef\@rbrace{\string}}
\newcommand\do@system[1]{%
\begingroup
\let\%\@percentchar
\let\#\@hashmark
\let\{\@lbrace
\let\}\@rbrace
\if@tempswa\expandafter\immediate\fi
\write18{#1}%
\endgroup
}
\makeatother
and in the argument also \#
, \{
and \}
can be used for escaping those characters.