What is the LaTeX 3 equivalent to \write18 if there is one? I want to call lilypond from within my TeX document.

  • Do you mean \tex_write:D? But :D means "Do not use it". Sep 14, 2013 at 15:33
  • 1
    \int_const:Nn \c_eighteen and then \iow_now:Nn \c_eighteen{...} is equivalent to \immediate\write18{\unexpanded{...}}; but probably one should define some new function based on this.
    – egreg
    Sep 14, 2013 at 16:57

2 Answers 2



Things have changed since 2013 and shell escape is now fully supported by expl3. The relevant section in the manual (as of 2021) is currently 10.7.

Getting the output from a command


For both functions the first n argument is an unquoted shell command (" quotes around it will be automatically supplied; the standard restrictions apply, namely that " cannot appear in this argument). The second argument is for “setup” (category code changes, for instance) that is applied to the tokens in the shell command. The third argument should be a token list variable. In the second function the T argument is returned if the command is well-formed and shell escape is enabled; otherwise the F argument is returned. The usual conventions for TF apply. The token list variable will contain the output of the shell command. If shell escape is disabled, the variable will contain \q_no_value.

This is the interface to `\input{|"..."}

Checking the shell escape status


is set to 0, 1 or 2 at the beginning of the job, with the usual meaning: 0 means shell escape is disabled; 1 that it is unrestricted; 2` means it is restricted.


are the predicates and the conditionals for testing the shell escape status.

Executing shell commands


will execute the command passed as argument, the x version will do full expansion of the argument. The execution is immediate.

This is the interface to \immediate\write18{...}


will execute the shell command at the next shipout (useful if the command to be executed needs as input the page number, for example).

This is the interface to \write18.


There is no function in LaTeX3, at the moment, dealing with \write18; it can be obtained by

\int_const:Nn \c_tobi_eighteen_int { 18 }
\int_const:Nn \c_tobi_shell_escape_int { \int_eval:n { \use:c { pdf@shellescape } } }
\cs_new_protected:Npn \tobi_system_exec_now:n #1
  \int_compare:nT { \c_tobi_shell_escape_int > 0 }
   { \iow_now:Nn \c_tobi_eighteen_int { #1 } }
\cs_new_protected:Npn \tobi_system_exec_shipout:n #1
  \int_compare:nT { \c_tobi_shell_escape_int > 0 }
   {  \iow_shipout:Nn \c_tobi_eighteen_int { #1 } }
\cs_generate_variant:Nn \tobi_system_exec_now:n { x }
\cs_generate_variant:Nn \tobi_system_exec_shipout:n { x }

%% Examples
\tobi_system_exec_now:n { ls }
\tl_set:Nn \l_tmpa_tl { ls }
\tobi_system_exec_now:x { \l_tmpa_tl }

You probably would want to add messages telling that things went wrong when shell escape is disabled; or just remove the \int_compare:nT thing.

I used the tobi prefix because using \system is probably a bad idea (I don't want to get slapped by Joseph on chat, you know).

  • Indeed, a good question here is what does and doesn't make sense interface-wise for this. As the team have not needed \write18 we've not worried out it. Notable of course is that catcodes might be an issue.
    – Joseph Wright
    Sep 14, 2013 at 19:55
  • @JosephWright Catcodes can surely be an issue; but I guess the function will be called with its argument coming from "user space". Otherwise, spaces must be ~, as usual. Setting up a good diagnostic system might be tricky, because of restricted shell.
    – egreg
    Sep 14, 2013 at 20:01
  • 1
    @JosephWright: don't you guys dare including a \write18 equivalent function in LaTeX3, I already printed interface3.pdf today! :) Sep 14, 2013 at 20:05

Since this question was answered, LaTeX3 has evolved. See section 10.7 Access to the shell, on interface3.pdf. In particular,


is replaced by


and its :x variant.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .