Std::process on windows is escaping raw literals which causes problems with chaining commands

This is implemented:


Given how messy the syntax of some legacy Windows commands can be, it may be useful to extend Command to support arbitrary syntax.

I think the simplest would be to add a method such as:

fn arguments_escaped(&mut self, the_command_line: &str) -> &mut Self

that takes the whole command line except the command name itself. So:

Command::new("foo").arguments_escaped("\\   args \" bar \" \"\"\" baz")

would execute command + space + arguments_escaped value verbatim, so GetCommandLineW in the executed command would be:

foo \   args " bar " """ baz

I've named it _escaped, meaning already escaped, because the caller is responsible for escaping arguments using some command-specific syntax (the name could be raw_args or anything else :bike:). The syntax is arbitrary as interpreted by the command being executed, so the Rust stdlib can't possibly know the syntax for all commands. User of Command would have to take that responsibility.

It's not exactly as bad as the Unix equivalent of passing a whole shell command as a string, because by default there's no dangerous shell syntax interpreted. It could be made dangerous if used as Command::new("cmd").arguments_escaped(format!("/c command {}", args)), but then it's equivalent of Command::new("bash").arg("-c").arg(format!("command {}", args)), which is a bad idea as well.

Linux, and probably other platforms, don't even have a concept of passing raw unparsed command string from the shell, so this method couldn't be portable. It could be OK if it was an extension trait in Windows-specific corner of the stdlib.

Alternatives:

  • Add .raw_arg(str)/.escaped_arg(str) that just appends a string to the command line (perhaps delimited by spaces). The upside is that it looks more like regular usage of Command, but the downside is that .raw_arg(one).raw_arg(two) could set expectation of passing two arguments, but the actual meaning of it is impossible to define.

  • Add .arg_with_syntax(str, ArgSyntax::DoesNotSupportNestedQuotes), .arg_with_syntax(str, ArgSyntax::ThisIsTheLastArgAndEverythingFromHereIsVerbatim) with quoting/sanitisation/mangling options for variously broken ad-hoc parsers.

  • Recognize the command being executed (e.g. dir, notepad, cmd /c, echo), and choose a different argument serialization syntax appropriate for whatever ad-hoc argument parser that command uses. The upside is that .arg() would magically work as intended, the downside is endless whack-a-mole with unlimited set of broken parsers. Also recognizing commands is unreliable (e.g. if the executable gets renamed).

5 Likes