Skip to content

How cmd.exe parses a command

John Stevenson edited this page Aug 5, 2016 · 3 revisions

The job of cmd.exe, the Windows command interpreter, is to evaluate and run a command that it has been given. This can either be from the command-line that it was created with, through user input from a console window, or the script in a batch file. This section describes how it processes a command from its command-line.

cmd performs its own argument parsing to obtain the command to be processed, described in How cmd.exe extracts a command. It then takes this command and performs a series of transformations, based on the presence of certain meta characters, to end up with one or more commands that it either handles internally, or passes to CreateProcess.

Meta characters

The following characters have a special meaning: " ^ & | < > ( ) % !

  • double-quote " toggles the start or end of a quoted-string.

Inside a quoted-string the characters ^ & | < > ( ) are treated as literal and have no special meaning. Outside a quoted-string they behave as follows:

  • caret ^ indicates that the next character is literal and has no special meaning. The caret is removed.
  • characters & | signify multiple commands.
  • characters < > signify IO redirection.
  • characters ( ) signify compound statements resulting in multiple commands.

The characters % ! signify variable expansion and are not affected by double-quotes.

Transformation

cmd performs its transformations in the following order:

  • Percent variable % expansion is done on the complete command. If the environment variable var is defined then %var% will be replaced by its value.
  • The command may be split into multiple commands if special characters are found.
  • Exclamation-mark variable ! expansion is done on each command, but only if DelayedExpansion is enabled and there is at least one exclamation-mark. If var is defined then !var! will be replaced by its value. The parser does this in two steps, the second one ignoring any double-quotes around ^ !.

Execution

The module to execute is identified from the start of each transformed command, delimited by whitespace outside a quoted-string.

If it is not known internally, cmd checks that it is a valid file, searching the current directory and PATH locations if required.

cmd handles batch files internally, but uses CreateProcess for executables, passing the module filename as lpApplicationName, and the command as lpCommandLine.

Detail

The above is a very generalized description so the following example provides more detail:

cmd.exe /c "SET "key=some thing" & prog paramA "%ProgramData%" > output.txt"

Extraction

The command to be processed is extracted:

SET "key=some thing" & prog paramA "%ProgramData%" > output.txt

Tranformation

Percent variable substitution is done first on the complete command:

SET "key=some thing" & prog paramA "C:\ProgramData" > output.txt

The next stage identifies & and > as special characters, resulting in two separate commands:

SET "key=some thing"
prog paramA "C:\ProgramData" > output.txt

DelayedExpansion is not enabled (cmd was not called with the V:on option) so the Transformation phase is complete.

Execution

The first module to execute is identified as SET and this is invoked internally. The next module is identified as prog which is not known to cmd so it searches the current directory and PATH locations for the first file named prog.*, appending file extensions from PATHEXT.

The > special character signifies output redirection, so cmd creates and opens output.txt in the current directory and adds its file-handle to the hStdOutput and hStdError members of the lpStartupInfo param.

The resulting call to CreateProcess looks like this:

CreateProcess (C:\projects\prog.exe, prog paramA "C:\ProgramData", ...);