== How Exim's _${run ...}_ string expansion operator does quoting Exim has [[a complicated string expansion system http://www.exim.org/exim-html-current/doc/html/spec_html/ch-string_expansions.html]] with various expansion operations. One of these is _${run}_, which runs a command to get its output (or just its exit status if you only care about that). The documentation for _${run}_ says, in part: > - ~~${run{ }{}{}}~~: The command > and its arguments are first expanded as one string. The > string is split apart into individual arguments by spaces, [...] > > Since the arguments are split by spaces, when there is a variable > expansion which has an empty result, it will cause the situation that > the argument will simply be omitted when the program is actually > executed by Exim. If the script/program requires a specific number > of arguments and the expanded variable could possibly result in this > empty expansion, the variable must be quoted. [...] What this documentation does not say is just how the command line is supposed to be quoted. For reasons to be covered later I have recently become extremely interested in this question, so I now have some answers. The short answer is that the command is interpreted in the same way as it is in [[the pipe transport http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_pipe_transport.html#SECThowcommandrun]]. Specifically: > Unquoted arguments are delimited by white space. If an argument > appears in double quotes, backslash is interpreted as an escape > character in the usual way. If an argument appears in single quotes, > no escaping is done. The usual way that backslashed escape sequences are handled is covered in [[character escape sequences in expanded strings http://www.exim.org/exim-html-current/doc/html/spec_html/ch-string_expansions.html#SECID82]]. Although the documentation for _${run}_ suggests using the ~~sg~~ operator to substitute dangerous characters, it appears that the much better approach is to use the ~~quote~~ operator instead. Using ~~quote~~ is simple and will allow you to pass through arguments unchanged, instead of either mangling characters with ~~sg~~ or doing complicated insertions of backslashes and so on. Note that this 'passing through unchanged' will include passing through literal newlines, which may be something you have to guard against in the command you're running. In fact, it appears that almost any time you're putting an Exim variable into a _${run}_ command line you should slap a _${quote:...}_ around it. Maybe the variable can't have whitespace or other dangerous things in it, but why take the chance? (I suspect that the _${run}_ documentation was written at a time that ~~quote~~ didn't exist, but I haven't checked this.) This documentation situation is less than ideal, to put it one way. It's possible that you can work all of this out without reading the Exim source code if you read all of the documentation at once and can hold it all in your head, but that's often not how documentation is used; instead it gets consulted as a sporadic reference. The _${run}_ writeup should at least have pointers to the sections with specific information on quoting, and ideally would have at least a brief inline discussion of its quoting rules. (I also believe that the rules surrounding _${run}_'s handling of argument expansion are dangerous and wrong, but it's too late to fix them now. See [[this entry ../unix/SecurelyRunningPrograms]] and also [[this one ../unix/SecureStringExpansion]].) === Sidebar: where in the Exim source this is Since I had to read the Exim source to get my answer, I might as well note down where I found things. _${run}_ itself is handled in the ((EITEM_RUN)) case in ((expand_string_internal)) in expand.c. The actual command handling is done by calling ((transport_set_up_command)), which is in transport.c. This handles single quotes itself in inline code but defers double quote handling to ((string_dequote)) in string.c, which calls ((string_interpret_escape)) to handle backslashed escape sequences. (It looks like ((transport_set_up_command)) is called by various different things under various circumstances that I'm not going to try to decode the Exim source code to nail down.)