How Command Line Parameters Are Parsed

by

David Deley

© 2009
(Updated 2014)


How to escape the special characters in your parameters

Contents:

*NIX (updated Feb. 2011)19
  1. How a New Process is Created on *nix (Unix, Linux, Ubuntu, Kubuntu, ...)
  2. Passing Parameters to a new process on *nix
    1. Example 1: Bash Shell
    2. Example 2: Ubuntu Desktop Launcher Icon (GNOME→Nautilus)
    3. Example 3: Kubuntu (KDE→Plasma)
  3. The *nix Parameter Parsing Rules

WINDOWS
  1. How a New Process is Created on Windows
  2. Passing Parameters to a new process on Windows
  3. How does a C/C++ program on Windows get argv[] ?
  4. Everyone Parses Differently
  5. The C/C++ Parameter Parsing Rules
    1. The rules changed in 2008 new!
    2. The documented and undocumented rules
    3. The C/C++ Parameter Parsing Rules Rephrased
    4. Summary of rules 5,6,7
    5. Examples
    6. Some Common Tasks
    7. The Microsoft Examples Explained
    8. Double Double Quote Examples
    9. How Triple Double Quotes Are Parsed
    10. How Quadruple Double Quotes Are Parsed
    11. The Microsoft C/C++ Command Line Parsing Algorithm
  6. Who Calls CreateProcess?
    1. ProgA.exe → CreateProcess()
    2. Command Prompt Window → CreateProcess()
  7. The Command Prompt Command Line Parameter Parsing Rules (cmd.exe)
    Putting It Together — How to Pass a Parameter to:
  8. a C/C++ Program from the Command Line
  9. a Batch File from the Command Line
  10. a VBScript, JScript, or WSH script from the Command Line
    1. The Windows Script Host (WSH) Parameter Parsing Rules
    2. The WSH Command Line Parameter Parsing Algorithm
    3. Examples
    4. Putting it together
  11. a Perl script from the Command Line
  12. a Python script from the Command Line
  13. a REXX script from the Command Line
  14. a RUBY script from the Command Line
  15. an AutoHotkey script from the Command Line


bar


*nix
(Unix, Linux, Ubuntu, Kubuntu, ...)19


1.  How a new process is created on *nix
On *nix, you launch a program using the execve API (or it's cousins execvp, execl, execlp, execle, and execvp). The interesting thing about these APIs is that they allow the caller to specify each of the command line arguments - the signature for execve is:

     int execve(const char *filename, char *const argv [], char *const envp[]);


2.  Passing Parameters to a new process on *nix
On *nix, the parameters are parsed off by whatever program creates the new process, before the new process is created.1

*nix
cmdline = "MyProg  Hello  Goodbye  Friday"     
 ↓ parse     
argv[] = MyProg.exe
Hello
Goodbye
Friday
     
 ↓ create new process     
execve(argv[])     New Process running MyProg.exe has argv[] 

2.1  Example 1: Bash Shell
If you launch a program using the Bash shell command line, The Bash shell is responsible for turning the string provided by the user into the argv[] argument vector which is then passed to the program. For the Bash shell parameter parsing rules, the following links provide some information:

2.2  Example 2: Ubuntu Desktop Launcher Icon (GNOME→Nautilus)
In Ubuntu a desktop launcher icon can be created by right-clicking on the desktop and selecting "Create Launcher". This will generate a GNOME launch file ~/Desktop/launcher-name.desktop This is a text file you can browse (have a look at one). In this text file is a line starting with Exec= where the command and any command line parameters are.17

So what happens when you double-click on this desktop icon?

Ubuntu uses the GNOME Desktop Environment, which in turn uses the Nautilus File Manager. When you double-click on a desktop launcher icon, the Nautilus File Manager parses the Exec= command line in the ~/Desktop/launcher-name.desktop file and calls execve passing it argv[]. So to know how your command line parameters are parsed you need to look into how Nautilus parses command lines. There's some good documentation here:

2.3  Example 3: Kubuntu (KDE→Plasma)
Kubuntu is based on Ubuntu but uses the KDE Plasma Desktop instead of GNOME. So, to determine how your command line is parsed in that environment, you'll need to look into KDE application launchers. This starts to get complicated, because according to the documentation there are three: Kickoff, classic K menu, or Lancelot Launcher.18

It gets even more complicated, because it's possible to install both the KDE Plasma Desktop (kubuntu-desktop) as well as the GNOME desktop (ubuntu-desktop) on the same machine.



3.  The *nix Parameter Parsing Rules
It all depends on who is processing your command line before the new process is created. On *nix, the parameters are parsed off by whatever program creates the new process.

This is all I have to say about *nix. The rest is about Windows.





bar



Windows®

1.  How a new process is created on Windows
On Windows, a new program is launched by calling the CreateProcess() API, which takes the command line as a string (the lpComandLine parameter to CreateProcess):

     int CreateProcess( ..., lpComandLine, ... )


2.  Passing Parameters to a new process on Windows
On Windows, the parameters are parsed off the command line after the new process is created, by the new process. It's considered the responsibility of the newly started application to call the GetCommandLine() API to retrieve the command line string and parse it (possibly using the CommandLineToArgvW() helper function).2

Windows
cmdline = "MyProg.exe  Hello  Goodbye  Friday"     
 ↓ create new process     
CreateProcess(cmdline)     New Process running MyProg.exe 
     ↓ call 
    GetCommandLine() 
     ↓ parse 
    
argv[] = MyProg.exe
Hello
Goodbye
Friday
 


3.  How does a C/C++ program on Windows get argv[]?
The C/C++ compiler which compiles the program secretly adds extra code to the executable that retrieves and parses the command line to extract the parameters before calling WinMain (or main). Thus, for a C/C++ executable on Windows, the parameter parsing rules are determined by the C/C++ compiler that compiled the program.


4.  Everyone Parses Differently
You'll get different results if you pass a command line to ShowParams.exe (written in C/C++), ShowParams.vbs (VBScript), or ShowParams.bat (batch file):

Sample Code: Results:
  1. ShowParams.exe
    ShowParams.exe (written in c)
    >ShowParams.exe "c:\test a\" "c:\test b\"
    param 0 = ShowParams.exe
    param 1 = c:\test a" c:\test
    param 2 = b"
    ( \" is interpreted as meaning 'a literal double quote.')

  2. C#ShowParams.exe
    C#ShowParams.exe (written in C#)
    >C#ShowParams.exe "c:\test a\" "c:\test b\"
    There are 2 program arguments
    c:\test a" c:\test
    b"
    ( \" is interpreted as meaning 'a literal double quote.')

  3. ShowParams.bat
    ShowParams.bat (a batch file)
    >ShowParams.bat "c:\test a\" "c:\test b\"
    param 1 = "c:\test a\"
    param 2 = "c:\test b\"
    (the double quotes are included as part of the parameter)

  4. ShowParams.vbs
    ShowParams.vbs (a Visual Basic script)
    >ShowParams.vbs "c:\test a\" "c:\test b\"
    param 0 = c:\test a\
    param 1 = c:\test b\
    (The double quotes are removed from the parameter)
Diagrams:
  1. ShowParams.exe
    ShowParams.exe     and     C#ShowParams.exe
    cmdline = "ShowParams.exe Hello Goodbye Friday"     
     ↓     
    CreateProcess(cmdline)     New Process running ShowParams.exe 
         ↓ call 
        GetCommandLine() 
         ↓ parse 
        
    argv[] = ShowParams.exe
    Hello
    Goodbye
    Friday
     

    The parameter parsing rules are determined by the C++ compiler that compiled ShowParams.exe



  2. ShowParams.bat
    ShowParams.bat
    cmdline = "ShowParams.bat Hello Goodbye Friday"     
     ↓     
    CreateProcess(cmdline)     New Process runs cmd.exe to process the batch file ShowParams.bat 
         ↓ call 
        GetCommandLine() 
         ↓ parse 
         %1 = Hello
    %2 = Goodbye
    %3 = Friday
     

    The parameter parsing rules are determined by cmd.exe which processes the batch file.



  3. ShowParams.vbs
    ShowParams.vbs
    cmdline = "ShowParams.vbs Hello Goodbye Friday"     
     ↓     
    CreateProcess(cmdline)     New Process runs WScript.exe to process the VBScript file ShowParams.vbs 
         ↓ call 
        GetCommandLine() 
         ↓ parse 
         Wscript.Arguments(0) = Hello
    Wscript.Arguments(1) = Goodbye
    Wscript.Arguments(2) = Friday
     

    The parameter parsing rules are determined by WScript.exe which processes the VBScript file.
Summary:
  1. Parameters passed to ShowParams.exe are parsed by ShowParams.exe . The parameter parsing rules are determined by the C++ compiler that compiled ShowParams.exe
  2. Parameters passed to ShowParams.bat are parsed by cmd.exe which is the program that processes batch files.
  3. Parameters passed to ShowParams.vbs are parsed by WScript.exe which is the program that processes VBScript files3
(Note: If you only see the first letter of each parameter, the parameters may be in Unicode format.)


5.  The C/C++ Parameter Parsing Rules
The documented program parameter parsing rules for Microsoft C/C++ compilers may be found by searching www.msdn.com for "Parsing C++ Command-Line Arguments".

  Visual C++ Versions and Corresponding .dll
msvcr120.dll — Visual C++ 2013 — (VC++ 12.0) — (released on October 17, 2013)
msvcr110.dl — Visual Studio 2012 — (VC++ 11.0)
msvcr100.dll — Visual Studio 2010 — (VC++ 10.0)
msvcr90.dll — Visual Studio 2008 — (VC++ 9.0) — [new command line parsing]
msvcr80.dll — Visual Studio 2005 — (VC++ 8.0)
msvcr71.dll — Visual C++ .NET 2003 — (VC++ 7.1)
msvcr70.dll — Visual C++ .NET 2002 — (VC++ 7.0)
msvcrt.dll — Visual C++ 6.0 — (VC6)
http://en.wikipedia.org/wiki/Visual_C%2B%2B
Redistribution of the shared C runtime component in Visual C++
http://support.microsoft.com/kb/326922


5.1  Here are the documented (and undocumented) rules:

  Note: The Rules Changed in 2008 new!
  1. Arguments are delimited by white space, which is either a space or a tab.
  2. The caret character (^) is not recognized as an escape character or delimiter. The character is handled completely by the command-line parser in the operating system before being passed to the argv array in the program.
    They are referring to the scenario discussed in sec. 6.2 below, where first the command line parser (cmd.exe) parses your command, handling such things as the escape character ^ , the redirection characters > & < , the pipe character | , the %  character which may identify environment variables that need to be expanded (e.g. %PROGRAMFILES%), etc. The rules here describe how your C/C++ executable will parse the lpCommandLine that was passed to CreateProcess() by cmd.exe or whoever calls CreateProcess().
  3. A string surrounded by double quotation marks ("string") is interpreted as a single argument, regardless of white space contained within. A quoted string can be embedded in an argument.
    The double quotes don't have to be around the whole parameter. A double quoted part may occur anywhere in the parameter.
  4. A double quotation mark preceded by a backslash (\") is interpreted as a literal double quotation mark character (").
  5. Backslashes are interpreted literally, unless they immediately precede a double quotation mark.
  6. If an even number of backslashes is followed by a double quotation mark, one backslash is placed in the argv array for every pair of backslashes, and the double quotation mark is interpreted as a string delimiter.
  7. If an odd number of backslashes is followed by a double quotation mark, one backslash is placed in the argv array for every pair of backslashes, and the double quotation mark is "escaped" by the remaining backslash, causing a literal double quotation mark (") to be placed in argv.
  8. The missing undocumented rule has to do with how doubledouble quotes ("") are handled:

5.2  The Microsoft C/C++ Parameter Parsing Rules Rephrased
These are the rules for parsing a command line passed by CreateProcess() to a program written in C/C++:
  1. Parameters are always separated by a space or tab (multiple spaces/tabs OK)
  2. If the parameter does not contain any spaces, tabs, or double quotes, then all the characters in the parameter are accepted as is (there is no need to enclose the parameter in double quotes).
  3. Enclose spaces and tabs in a double quoted part
  4. A double quoted part can be anywhere within a parameter
  5. 2n backslashes followed by a " produce n backslashes + start/end double quoted part
  6. 2n+1 backslashes followed by a " produce n backslashes + a literal quotation mark
  7. n backslashes not followed by a quotation mark produce n backslashes
  8. undocumented rules regarding double quotes:
    Prior to 2008:
    • A " outside a double quoted block starts a double quoted block
    • A " inside a double quoted block ends the double quoted block
    • If a closing " is followed immediately by another ", the 2nd " is accepted literally and added to the parameter.
    Post 2008:

5.3  Summary of rules 5,6,7:
Use"to start/end a double quoted part
Use\"to insert a literal "
Use\\"to insert a \ then start or end a double quoted part
Use \\\" to insert a literal \"
Use\to insert a literal \


5.4  Examples

Command-Line

argv[1]

Comment

CallMeIshmael

CallMeIshmael

a plain parameter can contain any characters except {space} {tab}  \  "

┌───────────────┐
"Call Me Ishmael"


Call Me Ishmael


spaces enclosed in a double quoted part

   ┌──────┐
Cal"l Me I"shmael


Call Me Ishmael


a double quoted part can be anywhere within a parameter

CallMe\"Ishmael
      ↑↑

 CallMe"Ishmael
       ↑


\" "

┌───────────────┐
"CallMe\"Ishmael"
       ↑↑


 CallMe"Ishmael
       ↑


\" "  (whether or not in a double quoted part)

┌─────────────────┐
"Call Me Ishmael\\"
                ↑↑↑


Call Me Ishmael\
    ↑          ↑


\\" \ + " (which may begin or end a double quoted part)

┌─────────────────┐
"CallMe\\\"Ishmael"
       ↑↑↑↑


 CallMe\"Ishmael
       ↑


\\\" \"     (\\ → \)  (\" → ")

a\\\b
 ↑↑↑

a\\\b
 ↑↑↑

backslashes not followed immediately by a double quotation mark are interpreted literally

"a\\\b"
  ↑↑↑

a\\\b
 ↑↑↑

whether or not the backslashes are in a double quoted part



5.5  Some Common Tasks

Command-Line

argv[1]

Comment

┌───────────────────┐
"\"Call Me Ishmael\""
 ↑↑               ↑↑


"Call Me Ishmael"
↑               ↑


the parameter includes double quotes

┌───────────┐
"C:\TEST A\\"
          ↑↑


C:\TEST A\
         ↑


the parameter includes a trailing slash

┌───────────────┐
"\"C:\TEST A\\\""
 ↑↑         ↑↑↑↑


"C:\TEST A\"
↑         ↑↑


the parameter includes double quotes and a trailing slash



5.6  The Microsoft Examples Explained

Command-Line Input

argv[1]

argv[2]

argv[3]

Comment

┌─────┐
"a b c"  d  e

┌─────┐
 a b c


d


e


spaces enclosed in double quotes

┌─────┐  ┌──┐
"ab\"c"  "\\"  d
   ↑↑     ↑↑↑

┌────┐
 ab"c
   ↑

┌─┐
 \ 
 ↑


d

\" "
\\" \ + begin or end a double quoted part

     ↓ ┌───┐ ↓
a\\\b d"e f"g h
 ↑↑↑


a\\\b

 ↑↑↑

↓     ↓
 de fg


h

backslashes not followed immediately by a double quotation mark are interpreted literally
 ↓   ↓  parameters are separated by spaces or tabs
 ┌───┐  a double quoted part can be anywhere within a parameter
the space enclosed in double quotation marks is not a delimiter

a\\\"b c d
 ↑↑↑↑

a\"b
 ↑↑

c

d

2n+1 backslashes before " → n backslashes + a literal "

     ┌───┐↓ ↓
a\\\\"b c" d e
 ↑↑↑↑↑


a\\b c


d


e

2n backslashes followed by a " produce n backslashes + start/end double quoted part.
 ↓   ↓  parameters are separated by spaces or tabs
 ┌───┐  a double quoted part can be anywhere within a parameter
the space enclosed in double quotation marks is not a delimiter



5.7  Double Double Quote Examples
(post 2008)

Command-Line Input

argv[1]

argv[2]

argv[3]

argv[4]

argv[5]

Comment

┌───────
"a b c""
      ↑↑


a b c"
     ↑

  • " Begin double quoted part.
  • "" while in a double quoted part → accept 2nd " literally, double quoted part continues

┌─────────────────┐
"""CallMeIshmael"""  b  c
 ↑↑             ↑↑


"CallMeIshmael"
↑             


b


c

  • " Begin double quoted part.
  • "" while in a double quoted part → accept 2nd " literally, double quoted part continues
  • " not followed by another " (i.e. not "") while in a double quoted part → ends the double quoted part
  • Parameters are delimited by spaces or tabs.

┌───────────────────┐
"""Call Me Ishmael"""
 ↑↑               ↑↑


"Call Me Ishmael"
↑               ↑

  • " Begin double quoted part.
  • "" while in a double quoted part → accept 2nd " literally, double quoted part continues
  • " not followed by another " (i.e. not "") while in a double quoted part → ends the double quoted part

┌──┐               ┌┐
""""Call Me Ishmael"" b c
 ↑↑


"Call


Me


Ishmael


b


c

  • " Begin double quoted part.
  • "" while in a double quoted part → accept 2nd " literally, double quoted part continues
  • " not followed by another " (i.e. not "") in a double quoted part → ends the double quoted part
  • Parameters are delimited by spaces or tabs.
  • (note "" outside of double quoted block begins and then immediately ends a double quoted part.)


(pre 2008)

Command-Line Input

argv[1]

argv[2]

argv[3]

Comment

┌─────┐
"a b c""
      ↑↑


a b c"
     ↑

"" while in a double quoted part → end double quoted part and accept 2nd " literally

┌┐              ┌┐
"""CallMeIshmael"""  b  c
 ↑↑              ↑↑


"CallMeIshmael"
↑             


b


c

" Begin double quoted part.
"" while in a double quoted part → end double quoted part and accept 2nd " literally

┌┐     ↓  ↓       ┌┐
"""Call Me Ishmael"""
 ↑↑                ↑↑


"Call


Me


Ishmael"
       ↑

Parameters are delimited by spaces or tabs.
" Begin double quoted part.
"" while in a double quoted part → end double quoted part and accept 2nd " literally

┌┐ ┌───────────────┐
""""Call Me Ishmael"" b c
 ↑↑                ↑↑


"Call Me Ishmael"
               ↑


b


c

Parameters are delimited by spaces or tabs.
" Begin double quoted part.
"" while in a double quoted part → end double quoted part and accept 2nd " literally




5.8  Triple Double Quotes
(post 2008)

How triple double quotes are parsed (post 2008)

                                     ..."""Call Me Ishmael"""...
                                        ↑↑               ↑↑↑↑
quote #1: Begin double quoted part──────┘├┘               ├┘├┘
quotes #2 & 3: Skip 1st " take 2nd " ────┘                 │
                                                          │ │
quotes 4 & 5: Skip 1st " take 2nd " ──────────────────────┘ │
quote #6: End double quoted part────────────────────────────┘


 >ShowParams.exe """Call Me Ishmael"""
 param 1 = "Call Me Ishmael"

an alternative method is

                   ┌───────────────┐
 >ShowParams.exe \""Call Me Ishmael"\"
 param 1 = "Call Me Ishmael"

or

                 ┌───────────────────┐
 >ShowParams.exe "\"Call Me Ishmael\""
 param 1 = "Call Me Ishmael"



(pre 2008)

How triple double quotes were parsed (pre 2008)

                                     ..."""Call Me Ishmael"""...
                                        ↑↑               ↑↑↑
quote #1: Begin double quoted part──────┘               │││
quote #2: End double quoted part─────────┘               │││
quote #3: and accept this " literally─────┘               │││
                                                          │││
quote #4: Begin double quoted part────────────────────────┘││
quote #5: End double quoted part───────────────────────────┘│
quote #6: and accept this " literally───────────────────────┘


 >ShowParams.exe """Call Me Ishmael"""
 param 1 = "Call
 param 2 = Me
 param 3 = Ishmael"

an alternative method is

 >ShowParams.exe \"Call Me Ishmael\"
 param 1 = "Call
 param 2 = Me
 param 3 = Ishmael"



5.9  Quadruple Double Quotes
(post 2008)

How quadruple double quotes are parsed(post 2008)

                                     ...""""Call me Ishmael""""...
                                        ↑↑↑↑              ↑↑↑↑
quote #1: Begin double quoted part──────┘├┘├┘              │├┘││
quotes #2 & 3: Skip 1st " take 2nd " ────┘                │ ││
quote #4: End double quoted part───────────┘               │ ││
                                                           │ ││
quote #5: Begin double quoted part─────────────────────────┘ ││
quotes #6 & 7: Skip 1st " take 2nd " ───────────────────────┘ ││
quote #8: End double quoted part──────────────────────────────┘
          Assuming this isn't another " ───────────────────────┘

 >ShowParams.exe """"Call Me Ishmael""""
 param 1 = "Call
 param 2 = Me
 param 3 = Ishmael"

an alternative method is

 >ShowParams.exe \"Call Me Ishmael\"
 param 1 = "Call
 param 2 = Me
 param 3 = Ishmael"



(pre 2008)

How quadruple double quotes are parsed (pre 2008)

                                     ...""""Call me Ishmael""""...
                                                       
quote #1: Begin double quoted part──────┘               │││
quote #2: End double quoted part─────────┘               │││
quote #3: and accept this " literally─────┘               │││
quote #4: Begin another double quoted part─┘               │││
                                                           │││
quote #5: End double quoted part───────────────────────────┘││
quote #6: and accept this " literally───────────────────────┘││
quote #7: Begin double quoted part───────────────────────────┘│
quote #8: End double quoted part──────────────────────────────┘
          If this was a double quote we'd accept it literally──┘

 >ShowParams.exe """"Call Me Ishmael""""
 param 1 = "Call Me Ishmael"

Note quotes #7,#8 are not necessary. They contribute nothing.

 >ShowParams.exe """"Call Me Ishmael""
 param 1 = "Call Me Ishmael"

an alternative method is

 >ShowParams.exe "\"Call Me Ishmael\""
 param 1 = "Call Me Ishmael"




5.10  The Microsoft C/C++ Command Line Parameter Parsing Algorithm
(pre 2008)
The following algorithm was reverse engineered by disassembling a small C program compiled using Microsoft Visual C++ and examining the disassembled code.

See msvcrtparsing.htm for the actual diasssembled code with annotations.

note if odd number of backslashes, we ignore last backslash and begin again.

1.Parse off parameter 0 (the program filename)
The entire parameter may be enclosed in double quotes (it handles double quoted parts)
(Double quotes are necessary if there are any spaces or tabs in the parameter)
There is no special processing of backslashes (\)
 
2.Parse off next parameter:
a.Skip over multiple spaces/tabs between parameters
LOOP
b.Count the backslashes (\). Let m = number of backslashes. (m may be zero.)
IF even number of backslashes (or zero)
c.IF next character following m backslashes is a double quote:
Even number of backslashes?
Yes. If we're not in a double quoted part, " begins a double quoted part.
Yes. If we're in a double quoted part, "" skip 1st take 2nd "
  If m is even (or zero)
  if currently in a double quoted part
  IF next character is also a "
  move to next character (the 2nd ". This character will be added to the parameter.)
ELSE
set flag to not add this " character to the parameter
toggle double quoted part flag (end double quoted part)
ENDIF
else
set flag to not add this " character to the parameter
endif
Endif
ENDIF
ENDIF
Add backslashes to output
m = m/2 (floor divide e.g. 0/2=0, 1/2=0, 2/2=1, 3/2=1, 4/2=2, 5/2=2, etc.)
d.add m backslashes
e.add this character to our parameter
ENDLOOP


(post 2008)

See msvcr100dparsing.htm for the actual diasssembled code with annotations.





6.  Who Calls CreateProcess?
So far we've talked about parsing the command line that got passed as the lpCommandLine parameter to CreateProcess(). But who calls CreateProcess? One possibility is you could write a small program which calls CreateProcess() passing it a command line.

6.1.  ProgA.exe → CreateProcess()
A small program ProgA.exe calls CreateProcess() passing it a command line:
ProgA.exe → CreateProcess()
ProgA.exe     
 ↓     
cmdline = "ShowParams.exe Hello Goodbye Friday"     
 ↓ create new process     
CreateProcess(cmdline)     New Process running ShowParams.exe 
     ↓ call 
    GetCommandLine() 
     ↓ parse 
    
argv[] = ShowParams.exe
Hello
Goodbye
Friday
 


Another possibility is you could open a Command Prompt window and type in a command:

6.2  Command Prompt Window → CreateProcess()
The command prompt window is program cmd.exe (go to START → RUN, enter "cmd"). Program cmd.exe displays the command prompt window, reads your command, and parses it handling such things as redirection characters (>) & (<), the pipe character (|), the escape character (^), identifying and expanding Environment Variables (e.g. %PROGRAMFILES%), etc. Then cmd.exe calls CreateProcess(), passing it a command line.4
Command Prompt Window (cmd.exe) → CreateProcess()
Command Prompt Window (cmd.exe)     
 ↓ get command from user     
command = "ShowParams.exe Hello Goodbye Friday < in.txt > out.txt"     
 ↓ parse and process command handling special characters like ^ < > | %
create a command line
     
cmdline = "ShowParams.exe  Hello  Goodbye  Friday"     
 ↓ create new process     
CreateProcess(cmdline)     New Process running ShowParams.exe 
      ↓ call 
     GetCommandLine() 
      ↓ parse 
     
argv[] = ShowParams.exe
Hello
Goodbye
Friday
 

Note here your command line is parsed twice:
  1. by the Command Prompt Window (cmd.exe)
  2. by ShowParams.exe
So if you want to get a parameter on the command line to ShowParams.exe, you first need to get it through the cmd.exe parser, then through the parser the Microsoft C/C++ compiler added to ShowParams.exe




7.  The cmd.exe Command Prompt Parsing Rules
The command prompt window is program cmd.exe5 (go to START → RUN, enter "cmd"). The command prompt window.

Escape Character
Double Quotes: Outside Double Quotes: Note ^ is also the line continuation character.

Inside Double Quotes:
Percent Sign:


7.1  Examples:
Outside of Double Quotes Escape The Essential Characters < > & | ^
>ShowParams.exe !\^"#$%^&'()*+,-./0123456789:;^<=^>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^^_`abcdefghijklmnopqrstuvwxyz{^|}~
                 └┴┘  ▲↑_                     ↑_ ↑_                               ↑_                             ↑_


Command Line = ShowParams.exe !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
↑_  These characters have been escaped with ^
 └┴┘  The " character has been escaped with ^ so it doesn't start a double quoted part when cmd.exe parses it.
Then ^" is escaped by \ so ShowParams.exe will see it as a literal " (Microsoft C/C++ parsing rules)
The result is:
\^" → cmd.exe parses to give \" → ShowParams.exe parses to give → "
 ▲  Note if this command line is to be put in a batch file, the % will need to be doubled.



Outside of Double Quotes It's OK to Escape Everything
>ShowParams.exe ^!^\^"^#^$^%^&^'^(^)^*^+^,^-^.^/^0^1^2^3^4^5^6^7^8^9^:^;^<^=^>^?^@^A^B^C^D^E^F^G^H^I^J^K^L^M^N^O^P^Q^R 
                  └┴┴┘     ▲

  ^S^T^U^V^W^X^Y^Z^[^\^]^^^_^`^a^b^c^d^e^f^g^h^i^j^k^l^m^n^o^p^q^r^s^t^u^v^w^x^y^z^{^|^}^~


Command Line = ShowParams.exe !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
→  line continues
└┴┴┘  The " character has been escaped with ^ so it doesn't start a double quoted part when cmd.exe parses it.
Then ^" is escaped by \ so ShowParams.exe will see it as a literal " (Microsoft C/C++ parsing rules)
itself is escaped by ^ just for the heck of it (it's OK to escape everything).
The result is:
^\^" → cmd.exe parses to give \" → ShowParams.exe parses to give → "
 ▲  Note if this command line is to be put in a batch file, the % will need to be doubled.



Inside Double Quotes Escape Nothing
                ┌─────────────────────────────────────────────────────────────────────────────────────────────┐
                │                                                                                             │

>ShowParams.exe "!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
                  ↑ ▲


Command Line = ShowParams.exe "!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
   " Outside a double quoted part, when not escaped with a ^, a double quote " produces a double quote " and begins a double quoted part
   " Inside a double quoted part, a double quote " produces a double quote " and ends the double quoted part
     The " character is always included as part of the parameter
   ↑ Note the " character has been left out of the sequence as it would end the double quoted part. (You can't escape a " while in a double quoted part. The closest we could get would be to use ^" which would give us a ^" and not end the double quoted part.)
▲  Note if this command line is to be put in a batch file, the % will need to be doubled.


7.2  More Examples:
Note: The result is what gets passed as part of the lpCommandLine argument to the CreateProcess() API. The newly created process still needs to retrieve the lpCommandLine string and parse off the parameters using it's own parsing rules (e.g. if it's a C/C++ program, it will use the Microsoft C/C++ parameter parsing rules to create the argv[] vector. See Putting It Together below for more on this).

Parameter

Result

Comment

PROGRAMFILES

PROGRAMFILES

 

"PROGRAMFILES"

"PROGRAMFILES"

 

%PROGRAMFILES%

C:\Program Files

an environment variable

"%PROGRAMFILES%"

"C:\Program Files"

" + an environment variable + "

%XYZ%

%XYZ%

(if XYZ is not an environment variable)


Some brief articles about Command Line parsing:




PUTTING IT TOGETHER:

8.
How To Pass A Parameter to:
a C/C++ Program from the Command Line

To get a parameter into a C/C++ program you need to work backwards through the two parsers it will go through:
  1. The cmd.exe command line parser parses your command & parameters
  2. The C/C++ program retrieves the resulting command line and parses off the parameters
Overview of steps:
  1. Start with the parameter you want
  2. Apply the Microsoft C/C++ parsing rules that ShowParams.exe will apply when parsing the command line it retrieves  [sec. 5]
  3. Apply the command line parsing rules that cmd.exe will apply when you enter the command and parameters  [sec. 7]
Step Details:
The steps to create your parameter are:
  1. Apply the Microsoft C/C++ parsing rules
    1. replace literal  "  with   \"
              literal \"  with  \\\"
              literal \\" with \\\\\"
    2. enclose the whole parameter in double quotes

  2. Apply the Command Line Parser (cmd.exe) parsing rules
    1. determine what cmd.exe will see as the quoted parts
    2. escape the special characters < > | & ^ not in a double quoted part
      • •the escape character for cmd.exe is ^
      • •it may also be necessary to escape ( ) @ !
      • •it's OK to escape everything
    3. If your command line will be placed in a batch file, double the % character8

Example 8.1: Command Line to C/C++ Program

Example 8.1a:     &<>^|()@ !

Parameter

Start with the parameter you want
(parameter includes a space)

&<>^|()@ !

1.Apply the Microsoft C/C++ parsing rules
a.
replace: literal  "  with   \"
literal \"  with  \\\"
literal \\" with \\\\\"

nothing to replace

b. enclose the whole parameter in double quotes
(because there's a space in the parameter)

┌──────────┐
"&<>^|()@ !"
↑          ↑

2.Apply the Command Prompt parsing rules (cmd.exe)
a. determine what cmd.exe will see as the quoted parts

┌──────────┐
"&<>^|()@ !"

b. escape the special characters not in double quoted parts:
( the escape character for cmd.exe is ^ )

Nothing to escape because it's all in a double quoted part
(as seen by cmd.exe)

c. if this will be placed in a batch file, double the % characters

no % in parameter

Result: To get desired parameter use this:

"&<>^|()@ !"

Example 8.1b:     &<>^|()@ !

Parameter

Start with the parameter you want
(same as example 1a)

&<>^|()@ !

1.Apply the Microsoft C/C++ parsing rules
a.
replace: literal  "  with   \"
literal \"  with  \\\"
literal \\" with \\\\\"

nothing to replace

b. enclose spaces in double quotes
(A double quoted part can be anywhere within a parameter)

&<>^|()@" "!
        ↑ ↑

2.Apply the Command Prompt parsing rules (cmd.exe)
a. determine what cmd.exe will see as the quoted parts

        ┌─┐
&<>^|()@" "!

b. escape the special characters not in double quoted parts:
( the escape character for cmd.exe is ^ )

                ┌─┐
^&^<^>^^^|^(^)^@" "^!
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑    ↑ 

c. if this will be placed in a batch file, double the % characters

no % in parameter

Result: To get desired parameter use this:

^&^<^>^^^|^(^)^@" "^!

Sample Test File:

Example 8.2: Command Line to C/C++ Program

Example 8.2:     &<>^|@()!"&<>^|@() !

Parameter

Start with the parameter you want

&<>^|@()!"&<>^|@()!

1.Apply the Microsoft C/C++ parsing rules
a.
replace: literal  "  with   \"
literal \"  with  \\\"
literal \\" with \\\\\"

&<>^|@()!\"&<>^|@()!
         ↑

b. enclose the whole parameter in double quotes

"&<>^|@()!\"&<>^|@()!"
↑                    ↑

2.Apply the Command Prompt parsing rules (cmd.exe)
a. determine what cmd.exe will see as the quoted parts

┌──────────┐         ┌───
"&<>^|()@!\"&<>^|@()!"

we have a problem in that the final " is interpreted by cmd.exe as opening a double quoted part. To avoid this, escape that last " ( the escape character for cmd.exe is ^ )

┌──────────┐
"&<>^|()@!\"&<>^|@()!^"
                     ↑

b. escape the other special characters not in double quoted parts:
( the escape character for cmd.exe is ^ )

┌──────────┐
"&<>^|@()!\"^&^<^>^^^|@()!^"
            ↑ ↑ ↑ ↑ ↑

c. if this will be placed in a batch file, double the % characters

no % in parameter

Result: To get desired parameter use this:

"&<>^|@()!\"^&^<^>^^^|@()!^"


Another way to get the same result would be at step 1b don't enclose the parameter in double quotes, then escape all special characters including the double quote so it doesn't start a double quoted part.

^&^<^>^^^|@()!\^"^&^<^>^^^|@()!
↑ ↑ ↑ ↑ ↑      ↑ ↑ ↑ ↑ ↑ ↑

Sample Test File:

Example 8.3: Command Line to C/C++ Program

Example 8.3a:     &<>^|@() !"&<>^|@() !

Parameter

Start with the parameter you want (parameter includes leading and trailing double quotes, plus a double quote inside, and two spaces)

"&<>^|@() !"&<>^|@() !"

1.Apply the Microsoft C/C++ parsing rules
a.
replace: literal  "  with   \"
literal \"  with  \\\"
literal \\" with \\\\\"

\"&<>^|@() !\"&<>^|@() !\"
↑           ↑           ↑

b. enclose the whole parameter in double quotes

┌──────────────────────────┐
"\"&<>^|@() !\"&<>^|@() !\""
↑                          ↑

2.Apply the Command Prompt parsing rules (cmd.exe)
a. determine what cmd.exe will see as the quoted parts

┌─┐           ┌───────────┐┌───
"\"&<>^|@() !\"&<>^|@() !\""

we have a problem in that the final " is interpreted by cmd.exe as opening a double quoted part. To avoid this, escape that last " ( the escape character for cmd.exe is ^ )

┌─┐           ┌───────────┐
"\"&<>^|@() !\"&<>^|@() !\"^"
                           ↑

b. escape the special characters not in double quoted parts:
( the escape character for cmd.exe is ^ )

┌─┐                ┌───────────┐
"\"^&^<^>^^^|@() !\"&<>^|@() !\"^"
   ↑ ↑ ↑ ↑ ↑

c. if this will be placed in a batch file, double the % characters

no % in parameter

Result: To get desired parameter use this:

"\"^&^<^>^^^|@() !\"&<>^|@() !\"^"


Another way to get the same result would be at step 2a just escape all special characters including all double quotes so there are no double quoted parts.

^"\^"^&^<^>^^^|@() !\^"^&^<^>^^^|@() !\^"^"
↑  ↑ ↑ ↑ ↑ ↑ ↑       ↑ ↑ ↑ ↑ ↑ ↑       ↑ ↑

Example 8.3b:     &<>^|@() !"&<>^|@() !

Parameter

Start with the parameter you want (same as 3a)

"&<>^|@() !"&<>^|@() !"

1.Apply the Microsoft C/C++ parsing rules
a.
replace: literal  "  with   \"
literal \"  with  \\\"
literal \\" with \\\\\"

\"&<>^|@() !\"&<>^|@() !\"
↑           ↑           ↑

b. enclose spaces in double quotes
(A double quoted part can be anywhere within a parameter)

          ┌─┐           ┌─┐
\"&<>^|@()" "!\"&<>^|@()" "!\"
          ↑ ↑           ↑ ↑

2.Apply the Command Prompt parsing rules (cmd.exe)
a. determine what cmd.exe will see as the quoted parts

 ┌────────┐ ┌──┐        ┌─┐  ┌───
\"&<>^|@()" "!\"&<>^|@()" "!\"

once again we have a problem in that the final " is interpreted by cmd.exe as opening a double quoted part. To avoid this, escape that last " ( the escape character for cmd.exe is ^ )

 ┌────────┐ ┌──┐        ┌─┐
\"&<>^|@()" "!\"&<>^|@()" "!\^"
                             ↑

b. escape the other special characters not in double quoted parts:
( the escape character for cmd.exe is ^ )

 ┌────────┐ ┌──┐             ┌─┐
\"&<>^|@()" "!\"^&^<^>^^^|@()" "!\^"
                ↑ ↑ ↑ ↑ ↑

c. if this will be placed in a batch file, double the % characters

no % in parameter

Result: To get desired parameter use this:

\"&<>^|@()" "!\"^&^<^>^^^|@()" "!\^"


Another way to get the same result would be at step 2a just escape all special characters including all double quotes so there are no double quoted parts.

\^"^&^<^>^^^|@()^" ^"!\^"^&^<^>^^^|@()^" ^"!\^"
 ↑ ↑ ↑ ↑ ↑ ↑    ↑  ↑   ↑ ↑ ↑ ↑ ↑ ↑    ↑  ↑   ↑

Sample Test File:

Example 8.4: Command Line to C/C++ Program

Example 8.4a:     "C:\TEST A\"

Parameter

Start with the parameter you want (parameter includes double quotes and a space)

"C:\TEST A\"

1.Apply the Microsoft C/C++ parsing rules
a.
replace: literal  "  with   \"
literal \"  with  \\\"
literal \\" with \\\\\"

\"C:\TEST A\\\"
↑          ↑↑

b. enclose the whole parameter in double quotes
(because there's a space in the parameter)

┌───────────────┐
"\"C:\TEST A\\\""
↑               ↑

2.Apply the Command Prompt parsing rules (cmd.exe)
a. determine what cmd.exe will see as the quoted parts

┌─┐            ┌┐
"\"C:\TEST A\\\""

b. escape the special characters not in double quoted parts:
( the escape character for cmd.exe is ^ )

No special characters to escape
(as seen by cmd.exe)

c. if this will be placed in a batch file, double the % characters

no % in parameter

Result: To get desired parameter use this:

"\"C:\TEST A\\\""


Another way to get the same result would be at step 2a just escape all special characters including all double quotes so there are no double quoted parts.

^"\^"C:\TEST A\\\^"^"
↑  ↑             ↑ ↑

Example 8.4b:     "C:\TEST A\"

Parameter

Start with the parameter you want (same as 4a)

"C:\TEST A\"

1.Apply the Microsoft C/C++ parsing rules
a.
replace: literal  "  with   \"
literal \"  with  \\\"
literal \\" with \\\\\"

\"C:\TEST A\\\"
↑          ↑↑

b. enclose spaces in double quotes
(A double quoted part can be anywhere within a parameter)

\"C:\TEST" "A\\\"
         ↑ ↑

2.Apply the Command Prompt parsing rules (cmd.exe)
a. determine what cmd.exe will see as the quoted parts

 ┌───────┐ ┌────┐ \"C:\TEST" "A\\\"

b. escape the special characters not in double quoted parts:
( the escape character for cmd.exe is ^ )

It's all in double quoted parts.
(as seen by cmd.exe)

c. if this will be placed in a batch file, double the % characters

no % in parameter

Result: To get desired parameter use this:

\"C:\TEST" "A\\\"


Another way to get the same result would be at step 2a just escape all special characters including all double quotes so there are no double quoted parts.

\^"C:\TEST^" ^"A\\\^"
 ↑        ↑  ↑     ↑

Sample Test File:

Example 8.5: Command Line to C/C++ Program

Example 8.5a:     "C:\TEST %&^ A\"

Parameter

Start with the parameter you want

"C:\TEST %&^ A\"

1.Apply the Microsoft C/C++ parsing rules
a.
replace: literal  "  with   \"
literal \"  with  \\\"
literal \\" with \\\\\"

\"C:\TEST %&^ A\\\"
↑              ↑↑

b. enclose the whole parameter in double quotes

┌───────────────────┐
"\"C:\TEST %&^ A\\\""

2.Apply the Command Prompt parsing rules (cmd.exe)
a. determine what cmd.exe will see as the quoted parts

┌─┐                ┌┐
"\"C:\TEST %&^ A\\\""

b. escape the special characters not in double quoted parts:
( the escape character for cmd.exe is ^ )

┌─┐                   ┌┐
"\"C:\TEST ^%^&^^ A\\\""
           ↑ ↑ ↑

c. if this will be placed in a batch file, double the % characters

┌─┐                    ┌┐
"\"C:\TEST ^%%^&^^ A\\\""
            ↑

Result: To get desired parameter use this:

"\"C:\TEST ^%%^&^^ A\\\""


Another way to get the same result would be at step 2a just escape all special characters including all double quotes so there are no double quoted parts.

^"\^"C:\TEST %^&^^ A\\\^"^"
↑  ↑          ↑ ↑      ↑ ↑

c. and if this will be placed in a batch file, double the % characters

^"\^"C:\TEST %%^&^^ A\\\^"^"
             ↑

Example 8.5b:     "C:\TEST %&^ A\"

Parameter

Start with the parameter you want (same as 5a)

"C:\TEST %&^ A\"

1.Apply the Microsoft C/C++ parsing rules
a.
replace: literal  "  with   \"
literal \"  with  \\\"
literal \\" with \\\\\"

\"C:\TEST %&^ A\\\"
↑              ↑↑

b. enclose spaces in double quotes
(A double quoted part can be anywhere within a parameter)

         ┌─┐   ┌─┐
\"C:\TEST" "%&^" "A\\\"
         ↑ ↑   ↑ ↑

2.Apply the Command Prompt parsing rules (cmd.exe)
a. determine what cmd.exe will see as the quoted parts

 ┌───────┐ ┌───┐ ┌────┐
\"C:\TEST" "%&^" "A\\\"

b. escape the special characters not in double quoted parts:
( the escape character for cmd.exe is ^ )

it's all in double quoted parts
(as seen by cmd.exe)

c. if this will be placed in a batch file, double the % characters

\"C:\TEST" "%%&^" "A\\\"
            ↑

Result: To get desired parameter use this:

"\"C:\TEST ^%%^&^^ A\\\""


Another way to get the same result would be at step 2a just escape all special characters including all double quotes so there are no double quoted parts.

\^"C:\TEST^" ^"%^&^^^" ^"A\\\^"
 ↑        ↑  ↑  ↑ ↑ ↑   ↑    ↑

c. and if this will be placed in a batch file, double the % characters

\^"C:\TEST^" ^"%%^&^^^" ^"A\\\^"
               ↑


Sample Test File:




9.
How To Pass A Parameter to:
a Batch File from the Command Line

To get a parameter into a batch file you need to work backwards through the two parsings it will go through:
  1. The cmd.exe command line parser parses your command line & parameters and then starts running the batch file
  2. The batch file retrieves the parameters, but when you use them, they get parsed again. Here's an example:
    1. a batch file line contains %1
    2. %1 is replaced with your parameter
    3. that line is then sent to the command line parser for execution, where it gets parsed
Overview of steps:
  1. Start with the parameter you want
  2. Apply the command line parsing rules that cmd.exe will apply when you enter the command and parameters  [sec. 7]
  3. Again, apply the command line parsing rules that cmd.exe will apply when you enter the command and parameters  [sec. 7]
Step Details:
The steps to create your parameter are:
  1. Apply the Command Line Parser (cmd.exe) parsing rules
    1. determine what cmd.exe will see as the quoted parts
    2. escape the special characters < > | & ^ not in a double quoted part
    3. again, escape the special characters < > | & ^ not in a double quoted part
      • •the escape character for cmd.exe is ^
      • •it may also be necessary to escape ( ) @ !
      • •it's OK to escape everything
    4. If your command line will be placed in a batch file, double the % character7

The Command Line to Batch File Rules:
Combining the two steps above gives us the following rules:

Space, Tab, Semicolon, Comma:
Note that you can't have a space within a parameter without having some double quotes around it somehow. All spaces must be within a double quoted part. Otherwise the space will act as a parameter delimiter. (Same with tabs, semicolons, commas.)
  1. Command line arguments can be separated by an unquoted semicolon or comma. This affects builtin commands like COPY and batch file parameters.
  2. If the command is called by name (no path), the following slash is treated a separator, as in DIR/P. This affects both builtin commands and external commands. Note: If you want to use NT-style slash-separated paths with DOS utilities you have to quote them (as in TYPE "C:/BOOT.INI").16

Example 9.1: Command Line to Batch File
Example 9.1:     &<>^|()@! Parameter

Start with the parameter you want

&<>^|()@!

1.Apply the Command Line to Batch File parsing rules
a. determine what cmd.exe will see as the quoted parts:

it's all unquoted

b. escape the special characters not in double quoted parts:

^^^&^^^<^^^>^^^^^^^|()@!
↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑

Result: To get desired parameter use this:

^^^&^^^<^^^>^^^^^^^|()@!

Sample Test File:
Example 9.2: Command Line to Batch File

Example 9.2:     &<>^|()@!

Parameter

Start with the parameter you want

┌─────────┐
"&<>^|()@!"

1.Apply the Command Line to Batch File parsing rules
a. determine what cmd.exe will see as the quoted parts:

it's all in a double quoted part

b.escape the special characters not in double quoted parts:

Nothing to escape because it's all in a double quoted part
(as seen by cmd.exe)

Result: To get desired parameter use this:

"&<>^|()@!"

Sample Test File:
Example 9.3: Command Line to Batch File

Example 9.3:     &<>^|()@!"&<>^|()@!

Parameter

Start with the parameter you want

&<>^|()@!"&<>^|()@!

1.Apply the Command Line to Batch File parsing rules
a. determine what cmd.exe will see as the quoted parts:

┌─────────┐         ┌───
"&<>^|()@!"&<>^|()@!"

we have a problem in that the final " is interpreted by cmd.exe as opening a double quoted part. To avoid this, escape that last " 

┌─────────┐
"&<>^|()@!"&<>^|()@!^^^"
                    ↑↑↑

b.escape the special characters not in double quoted parts:

┌─────────┐
"&<>^|()@!"^^^&^^^<^^^>^^^^^^^|()@!^^^"
           ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑

Result: To get desired parameter use this:

"&<>^|()@!"^^^&^^^<^^^>^^^^^^^|()@!^^^"

Though not necessary, it's OK to escape the rest of the characters:

┌─────────┐
"&<>^|()@!"^^^&^^^<^^^>^^^^^^^|^^^(^^^)^^^@^^^!^^^"
                               ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑

An easier way to get the same result would be to escape the " within the parameter so it doesn't end the double quoted part. Then nothing else needs to be escaped since it's all in a double quoted part.

┌────────────────────┐
"&<>^|()@!\"&<>^|()@!"
          ↑

Another way to get the same result would be to escape all the special characters including all the " so nothing is in a double quoted part:

^^^"^^^&^^^<^^^>^^^^^^^|()@!^^^"^^^&^^^<^^^>^^^^^^^|()@!^^^"

As before, though it's not necessary, it is OK to escape the rest of the characters:

^^^"^^^&^^^<^^^>^^^^^^^|^^^(^^^)^^^@^^^!^^^"^^^&^^^<^^^>^^^^^^^|^^^(^^^)^^^@^^^!^^^"
                        ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑                         ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑

Sample Test Files:
all 5 test files should produce the same result



10.
How To Pass A Parameter to:
a VBScript, JScript, or WSH Script
from the Command Line
VBScript (.vbs), JScript9 (.js), and WSH (.wsh) scripts are run by program wscript.exe, which is the Microsoft® Windows® Script Host (WSH). WSH is a language-independent scripting host for Windows Script compatible scripting engines. Microsoft provides both Microsoft Visual Basic Script and JScript scripting engines with WSH. Windows Script Host executes scripts that exist outside an HTML or ASP page and that stand on their own as text files.10
     Example:
      > C:\WINDOWS\system32\wscript.exe ShowParams.vbs hello goodbye Friday
When you run ShowParams.vbs you'll notice the window title says, "Window Script Host".

“If you want to get picky, the truth is that you can’t read command-line arguments using VBScript; that’s because VBScript doesn’t know anything about command-line arguments. But that’s all right; after all, VBScript doesn’t have to know anything about command-line arguments. That’s because Windows Script Host takes care of all that stuff.

“Any time you supply a command-line argument to a script that runs under Windows Script Host (that includes JScript scripts as well as VBScript scripts) those arguments are automatically stored in the Wscript.Arguments collection.”

     —Hey, Scripting Guy! 2008 Winter Scripting Games: Retrieving Command-Line Arguments
          http://www.microsoft.com/technet/scriptcenter/funzone/games/tips08/gtip0104.mspx

drscripto


On startup wscript.exe calls GetCommandLine() to get the command line, then calls wscript!SplitCommandLine(), which parses off the parameters. The rules for WSH command line parameter parsing are simple:

10.1  The WSH Command Line Parameter Parsing Rules:

10.2  The Microsoft® Windows® Script Host (WSH) Command Line Parameter Parsing Algorithm:
The following algorithm was reverse engineered by disassembling and examining wscript.exe and cscript.exe:

Algorithm:

  1. call Kernel32.dll!GetCommandLine() to get the command line
  2. make a copy of the command line
  3. call wscript!SplitCommandLine() dry run to determine the number of parameters
  4. allocate space for argv[] array
  5. call wscript!SplitCommandLine() to parse parameters and fill in argv[] array
wscript!SplitCommandLine() builds an argv[] array of where each parameter begins, and writes a terminating NULL at the end of each parameter.

Splitting the Command Line to get Parameters

start with: ShowParams.exe hello goodbye Friday
end with:   ShowParams.exe0hello0goodbye0Friday0
            ↑              ↑     ↑       
 argv[]     │              │     │       
param 0: ───┘              │     │       
param 1: ──────────────────┘     │       
param 2: ────────────────────────┘       
param 3: ────────────────────────────────┘

loop
   parse off next parameter:
   skip over spaces, tabs
   clear " flag
   save starting address of this parameter
   LOOP
      process this character:
      If space or tab
         if " flag set
            accept this space or tab as part of the parameter
         else
            write a 0 here to terminate this parameter
            and goto parse off next parameter
      Else if "
         toggle " flag, strip " (shift rest of line left 1 char)
      move to next char
   ENDLOOP
endloop
Notes:

10.3  Putting it together:
When you launch a VBScript, JScript, or WSH script from the command line, your command line goes through two parsers:
  1. First the cmd.exe command line parser parses your command & parameters, using its cmd.exe parsing rules. It builds a command line, and calls CreateProcess() passing it the command line it built.
  2. Then the Windows Script Host retrieves that resulting command line and parses off the parameters, using its WSH parsing rules.
So to get a parameter into a VBScript, JScript, or WSH script, you need to work backwards through the two parsers it will go through:
  1. Start with the parameter you want
  2. Apply the WSH parsing rules that Windows Script Host will apply when parsing the command line it retrieves
  3. Then apply the command line parsing rules that cmd.exe will apply when you enter the command and parameters
Step Details:
The steps to create your parameter are:
  1. Apply the WSH parsing rules:
    1. if there are any spaces or tabs within a parameter, add some " so they are enclosed in a double quoted part
      •                                                         ┌───────────────┐
        •you may enclose the entire parameter in double quotes: "Call Me Ishmael"
      •                                                           ┌─┐  ┌─┐
        •or you may enclose just the spaces in double quotes: Call" "Me" "Ishmael
      •                                  ┌────────┐
        •or you can make a mess of it: Ca"ll Me Is"hmael

  2. Apply the Command Line Parser (cmd.exe) parsing rules
    1. determine what cmd.exe will see as the double quoted parts
    2. escape the special characters < > | & ^ not in a double quoted part
      • •the escape character for cmd.exe is ^
      • •it may also be necessary to escape ( ) @ !
      • •it's OK to escape everything
    3. If your command line will be placed in a batch file, double the % character11

10.4  Sample Scripts:

Sample 'Show Parameters' scripts:

VBScript: JScript:

11.
How To Pass A Parameter to
a Perl script from the command line
ActivePerl12 and Strawberry Perl13 both call MSVCRT.dll!__getmainargs which follows the Microsoft C/C++ Parameter Parsing Rules. Therefore the steps are:
  1. Start with the parameter you want
  2. Apply the Microsoft C/C++ parsing rules that ShowParams.exe will apply when parsing the command line it retrieves  [sec. 5]
  3. Apply the command line parsing rules that cmd.exe will apply when you enter the command and parameters  [sec. 7]
See sec. 8: How To Pass A Parameter to: a C/C++ Program from the Command Line above.

Sample 'Show Parameters' Perl script:

12.
How To Pass A Parameter to
a Python script from the command line

Python™14 is written in C and obtains its parameters via the argv[] vector.15 It thus uses the Microsoft C/C++ Parameter Parsing Rules. Therefore the steps are:
  1. Start with the parameter you want
  2. Apply the Microsoft C/C++ parsing rules that ShowParams.exe will apply when parsing the command line it retrieves  [sec. 5]
  3. Apply the command line parsing rules that cmd.exe will apply when you enter the command and parameters  [sec. 7]
See sec. 8: How To Pass A Parameter to: a C/C++ Program from the Command Line above.

Sample 'Show Parameters' Python script for Python version 2: Sample 'Show Parameters' Python script for Python version 3:
Note: Python version 3 is incompatible with Python version 2. Guido van Rossum wrote "Python 3.0, also known as Python 3000 or Py3K, is the first ever intentionally backwards incompatible Python release." In particular, print statements that would work with pre-3 versions of Python will not work in 3.x. The change of "print" from a statement to a function is identified as a common stumbling block on this page on what's new in Python 3.0. http://docs.python.org/3.1/whatsnew/3.0.html


13.
How To Pass A Parameter to
a REXX script from the command line

8/24/2009 Under Construction...

Sample 'Show Parameters' REXX script:

13.
How To Pass A Parameter to
a RUBY script from the command line

Ruby attempts to mimic the Microsoft C/C++ parameter parsing rules, but the current versions, 1.8.6 & 1.9.1, have a bug in them so they don't work properly.

(file Win32.c routine rb_w32_cmdvector, the memcpy statement needs to copy one more character to include the trailing NULL.)

Sample 'Show Parameters' RUBY script:

15.
How To Pass A Parameter to
an AutoHotkey script from the command line

AutoHotkey is written in C++ and obtains its parameters via the __argv[] vector. Thus it uses the Microsoft C/C++ Parameter Parsing Rules. Therefore the steps are:
  1. Start with the parameter you want
  2. Apply the Microsoft C/C++ parsing rules that ShowParams.exe will apply when parsing the command line it retrieves  [sec. 5]
  3. Apply the command line parsing rules that cmd.exe will apply when you enter the command and parameters  [sec. 7]
See sec. 8: How To Pass A Parameter to: a C/C++ Program from the Command Line above.

Sample 'Show Parameters' AutoHotkey script:


Footnotes:
1. Larry Osterman's WebLog The Windows command line is just a string...
http://blogs.msdn.com/larryosterman/archive/2007/10/03/the-windows-command-line-is-just-a-string.aspx
Note even though the execl() API allows you to specify a command line string, the execl() API parses that command line string into argv and argc before calling execve().
2. ibid.
3. or possibly CScript.exe; WScript.exe is the Windows version, CScript.exe is the console version. You'll find them in the System32 directory.
4. In some cases cmd.exe may call ShellExecute() which eventually calls CreateProcess(), passing it a command line.
5. On Windows 95,98,ME the Command Prompt Window program was COMMAND.COM . The parsing rules are the same. (Back then it was also known as the DOS Prompt, or MS-DOS Prompt. Technically COMMAND.COM is DOS. Note there are other Command Prompt Window programs such as JPSoft's "Take Command". (http://jpsoft.com)
Note the following CP/M legacy constructs: 1. Command line arguments can be separated by an unquoted semicolon or comma. This affects builtin commands like COPY and batch file parameters. In particular, I can think of no way to pass A;B (without quotes) as a paramater to a batch file. 2. If the command is called by name (no path), the following slash is treated a separator, as in DIR/P. This affects both builtin commands and external commands. Note: If you want to use NT-style slash-separated paths with DOS utilities you have to quote them (as in TYPE "C:/BOOT.INI").
6. It's been documented in the past, such as here:
"Percent Signs Stripped from Batch File Text" http://support.microsoft.com/kb/75634
and it's mentioned in current documentation here (last sentence of the "Copy Examples" section):
"dtutil Utility" http://msdn.microsoft.com/en-us/library/ms162820.aspx
Note: JPSoft's Take Command command line utility processes % differently. You'll need to quadruple the % char (http://jpsoft.com)
7. See footnote 6
8. See footnote 6
9. JScript is Microsoft's own version of JavaScript.
10. "Windows Script Host Basics" http://msdn.microsoft.com/en-us/library/ec0wcxh3(VS.85).aspx
"Description of Windows Script Host (WSH)" http://support.microsoft.com/kb/188135
"Hosting Environments and Script Engines" http://msdn.microsoft.com/en-us/library/s4axe076(VS.85).aspx
11. See footnote 6
12. http://www.activestate.com/activeperl/
13. http://strawberryperl.com/
14. http://www.python.org/
15. Technically, WinMain in WinMain.c calls Py_main in main.c passing it __argc and __wargv as argc[] and argv[] respectively.
16. Thanks to Christopher Yeleighton for these two points.
17. YoLinux.com: GNOME desktop basics → GNOME Desktop Launcher
18. The KDE Menu Editor Handbook
19. Thanks to András Korn for assistance in updating the *nix section (Feb. 2011).



David Deley © 2009
http://members.cox.net/deleyd/

Last update: February 9, 2011