How Command Line Parameters Are Parsed
by
David Deley
© 2009
(Updated 2014)
(Updated 2016)
(Updated 2019)
(Updated 2020)
How to escape the special characters in your parameters
Contents:
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:
- ShowParams.c
- #include "stdafx.h"
int main(int argc, char* argv[])
{
for (int i = 0; i < argc; ++i)
{
printf("param %d = ",i);
puts(argv[i]);
printf("\n");
}
return 0;
}
(Note: Avoid using printf when printing parameters,
as the parameter may contain a % which would be interpreted
by printf as a conversion specifier.
The program may crash with a bizarre error, such as
"runtime error R6002 - Floating point not loaded".)
(Note: If we started this function with
wmain or _tmain
then argv[] would point to wide character (unicode) strings.
[Technically I'm not sure if they are UTF-16LE or UCS-2. I have 2 old posts
discussing the basics of Unicode:
I also wrote a short book on Unicode:
- ShowParamsC#.cs
- using System;
namespace ShowParams
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("There are {0} program arguments", args.Length);
foreach (string arg in args)
{
Console.WriteLine(arg);
}
}
}
}
- ShowParams.bat
- @echo off
echo Param1 = %1
echo Param2 = %2
echo Param3 = %3
- ShowParams.vbs
- If Wscript.Arguments.Count = 0 Then
Wscript.echo "No parameters found"
Else
i=0
Do until i = Wscript.Arguments.Count
Parms = Parms & "Param " & i & " = " & Wscript.Arguments(i) & " " & vbcr
i = i+1
loop
Wscript.echo parms
End If
Results:
- 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.')
- 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.')
- 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)
- 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:
- 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
- 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.
- 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:
- Parameters passed to ShowParams.exe are parsed by ShowParams.exe . The parameter parsing rules are determined by the C++ compiler that compiled ShowParams.exe
- Parameters passed to ShowParams.bat are parsed by cmd.exe which is the program that processes batch files.
- 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".
- There is separate documentation for each version of Microsoft's C/C++ compiler.
- Fortunately the documentation is identical for all of them.
- Unfortunately the documentation isn't complete.
- The implementation changed in 2008, which isn't documented.
- Fortunately you're reading this.
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)
Redistribution of the shared C runtime component in Visual C++
5.1 Here are the documented (and undocumented) rules:
Note: The Rules Changed in 2008 new!
- Arguments are delimited by white space, which is either a space or a tab.
- 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().
- 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.
- A double quotation mark preceded by a backslash (\") is interpreted as a literal double quotation mark character (").
- Backslashes are interpreted literally, unless they immediately precede a double quotation mark.
- 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.
This includes any trailing double quote enclosing a parameter.
- 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.
- The missing undocumented rule has to do with how doubledouble quotes ("") are handled:
- Prior to 2008:
If a closing " is followed immediately by another ", the 2nd " is accepted literally and added to the parameter.
- After 2008
- A double quote encountered outside a double quoted block starts a double quoted block.
- A double quote encountered inside a double quoted block:
- not followed by another double quote ends the double quoted block.
- followed immediately by another double quote (e.g. ""), a single double quote is added to the output, and the double quoted block continues.
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++:
- Parameters are always separated by a space or tab (multiple spaces/tabs OK)
- 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).
- Enclose spaces and tabs in a double quoted part
- A double quoted part can be anywhere within a parameter
- 2n backslashes followed by a " produce n backslashes + start/end double quoted part
- 2n+1 backslashes followed by a " produce n backslashes + a literal quotation mark
- n backslashes not followed by a quotation mark produce n backslashes
- 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:
- Outside a double quoted block a " starts a double quoted block.
- Inside a double quoted block a " followed by a different character (not another ") ends the double quoted block.
- Inside a double quoted block a " followed immediately by another " (i.e. "") causes a single " to be added to the output, and the double quoted block continues.
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
The following algorithm was reverse engineered by disassembling a small C
program compiled using Microsoft Visual C++ and examining the
disassembled code.
(post 2008)
See
msvcr100dparsing.htm for the actual diasssembled code with annotations.
[
画像:Parsing flow diagram for C/C++]
(2020: Thank you to Pepa Stefan for noting an error in the earlier version of the diagram.)
(pre 2008)
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
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:
- by the Command Prompt Window (cmd.exe)
- 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.exe
5
(go to START → RUN, enter "
cmd").
The command prompt window.
Escape Character
- ^ is the escape character for commands passed to cmd.exe
Double Quotes:
- An unescaped " will begin or end a double quoted part, and the double quote will be included as part of the parameter.
- ^" outside a double quoted part will insert a " but will not start a double quoted part.
- Environment variables are expanded both inside and outside double quotes.
Outside Double Quotes:
- Use ^ outside double quotes to escape < > & | ^
to insert < use ^<
to insert > use ^>
to insert | use ^|
to insert ^ use ^^
to insert " and begin a double quoted part use "
to insert " and not begin a double quoted part use ^"
- sometimes it may be necessary to also escape ( ) @ !
- It's OK to escape everything
Note ^ is also the line continuation character.
Inside Double Quotes:
- Inside Double Quotes, everything is taken literally
- ^" gives ^" but does not end a double quoted part
- Environment variable expansion is still performed inside double quotes
Percent Sign:
- If your command line will be placed in a batch file, double the % character6
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).
7.1 Examples:
| Outside of Double Quotes Escape The Essential Characters < > & | ^ |
>ShowParams.exe !\^"#$%^&'()*+,-./0123456789:;^<=^>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^^_`abcdefghijklmnopqrstuvwxyz{^|}~
└┴┘ ▲↑_ ↑_ ↑_ ↑_ ↑_
lpCommandLine = 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^{^|^}^~
lpCommandLine = 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{|}~"
↑ ▲
lpCommandLine = 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 Environment Variables:
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.
A command line passed to a C/C++ program passes through two parsers:
- The cmd.exe command line parser parses your command & parameters
- The C/C++ program retrieves the resulting command line and parses off the parameters
Here are some examples:
| Parsing Example 1 |
1. ShowParams.exe Bed Bath ^& Beyond
└┘
↓
↓
2. ↓ Bed Bath & Beyond
↓
↓
↓
3. ↓ Bed Bath & Beyond
↓ ↓ ↓ ↓ ↓
↓ ↓ ↓ ↓ ↓
↓ ↓ ↓ ↓ ↓
4. argv[0] argv[1] ↓ ↓ ↓
argv[2] ↓ ↓
argv[3] ↓
argv[4]
param 0 = ShowParams.exe
param 1 = Bed
param 2 = Bath
param 3 = &
param 4 = Beyond
|
1. cmd.exe command line parser interprets ^& as an escaped & character so it does not interpret this as “start a new command.” (It's possible to put more than one DOS command on a command line by separating them with the & character.)
2. C/C++ command line parser receives this. There are no double quotes for it to process.
3. C/C++ command line parser parses off the command line parameters into the argv[] array.
| Parsing Example 2 |
┌─────┐
│ │
1. ShowParams.exe Bed \"Bath\" ^& Beyond
└┘
↓
↓
2. ↓ Bed \"Bath\" & Beyond
↓ └┘ └┘
↓
↓
3. ↓ Bed "Bath" & Beyond
↓ ↓ ↓ ↓ ↓
↓ ↓ ↓ ↓ ↓
↓ ↓ ↓ ↓ ↓
4. argv[0] argv[1] ↓ ↓ ↓
argv[2] ↓ ↓
argv[3] ↓
argv[4]
param 0 = ShowParams.exe
param 1 = Bed
param 2 = "Bath"
param 3 = &
param 4 = Beyond
|
1. cmd.exe command line parser interprets the first " as “Start a double quoted part” and the second " as “End the double quoted part.” cmd.exe does not remove the double quote characters. (Note that these double quotes are not escaped with the ^ character, which is the escape character for cmd.exe. Also note the \ character is treated as an ordinary character by cmd.exe)
cmd.exe command line parser interprets ^& as an escaped & character so it does not interpret this as “start a new command.” (It's possible to put more than one DOS command on a command line by separating them with the & character.)
2. C/C++ command line parser receives this. The C/C++ parser interprets \" as an escaped double quote so neither one starts a double quoted part.
3. C/C++ command line parser parses off the command line parameters into the argv[] array.
| Parsing Example 3 |
1. ShowParams.exe ^"Bed Bath ^& Beyond^"
└┘ └┘ └┘
↓
↓ ┌─────────────────┐
↓ │ │
2. ↓ "Bed Bath & Beyond"
↓
↓ ↓
↓ ↓
↓
3. ↓ Bed Bath & Beyond
↓ ↓
↓ ↓
↓ ↓
4. argv[0] argv[1]
param 0 = ShowParams.exe
param 1 = Bed Bath & Beyond
|
1. cmd.exe command line parser interprets ^" as an escaped " character so it does not start or end a double quoted part.
cmd.exe command line parser interprets ^& as an escaped & character so it does not interpret this as “start a new command.” (It's possible to put more than one DOS command on a command line by separating them with the & character.)
2. C/C++ command line parser receives this. The C/C++ parser interprets " as “start or end a double quoted part” and the double quotes are removed.
3. C/C++ command line parser parses off the command line parameters into the argv[] array.
| Parsing Example 4 |
1. ShowParams.exe ^"Bed \^"Bath\^" ^& Beyond^"
└┘ └┘ └┘ └┘ └┘
↓
↓ ┌─────────────────────┐
↓ │ │
2. ↓ "Bed \"Bath\" & Beyond"
↓ └┘ └┘
↓
↓ ↓
↓ ↓
↓
3. ↓ Bed "Bath" & Beyond
↓ ↓
↓ ↓
↓ ↓
4. argv[0] argv[1]
param 0 = ShowParams.exe
param 1 = Bed "Bath" & Beyond
|
1. cmd.exe command line parser interprets ^" as an escaped " character so it does not interpret this as “Start a double quoted part.”
cmd.exe command line parser interprets ^& as an escaped & character so it does not interpret this as “Start a new command.” (It's possible to put more than one DOS command on a command line by separating them with the & character.)
2. C/C++ command line parser receives this. The C/C++ parser interprets \" as an escaped double quote so they do not start a double quoted part.
3. C/C++ command line parser parses off the command line parameters.
It gets harder when double quotes are not escaped with ^ as cmd.exe will now interpert them as “Start or end a double quoted part.”
| Parsing Example 5 |
┌──────────────────┐
│ │
1. ShowParams.exe "Bed Bath ^& Beyond"
↓
↓ ┌──────────────────┐
↓ │ │
2. ↓ "Bed Bath ^& Beyond"
↓
↓ ↓
↓ ↓
↓
3. ↓ Bed Bath ^& Beyond
↓ ↓
↓ ↓
↓ ↓
4. argv[0] argv[1]
param 0 = ShowParams.exe
param 1 = Bed Bath ^& Beyond
|
1. cmd.exe command line parser interprets the first " as “Start a double quoted part” and the second " as “End the double quoted part.” cmd.exe does not remove the double quote characters.
Inside the double quoted part cmd.exe interprets all characters literally, including ^ and &
2. C/C++ command line parser receives this. The parser interprets the first " as “Start a double quoted part” and the second " as “End the double quoted part.” The double quotes are removed.
3. C/C++ command line parser parses off the command line parameters into the argv[] array.
| Parsing Example 6 |
1. ShowParams.exe ^"Bed Bath \^" Beyond^"
└┘ └┘ └┘
↓
↓ ┌──────────────────┐
↓ │ │
2. ↓ "Bed Bath \" Beyond"
↓
↓ ↓
↓ ↓
↓
3. ↓ Bed Bath " Beyond
↓ ↓
↓ ↓
↓ ↓
4. argv[0] argv[1]
param 0 = ShowParams.exe
param 1 = Bed Bath " Beyond
|
1. cmd.exe command line parser interprets ^" as an escaped " character so it does not start or end a double quoted part.
cmd.exe command line parser interprets ^& as an escaped & character so it does not interpret this as “start a new command.” (It's possible to put more than one DOS command on a command line by separating them with the & character.)
2. C/C++ command line parser receives this. The parser interprets " as “start or end a double quoted part” and the double quotes are removed.
3. C/C++ command line parser parses off the command line parameters into the argv[] array.
| Parsing Example 7 |
1. ShowParams.exe ^"Bed Bath \\\^" Beyond^"
└┘ └┘ └┘
↓
↓ ┌────────────────────┐
↓ │ │
2. ↓ "Bed Bath \\\" Beyond"
└┴┴┘
↓
↓ ↓
↓ ↓
↓
3. ↓ Bed Bath \" Beyond
↓ ↓
↓ ↓
↓ ↓
4. argv[0] argv[1]
param 0 = ShowParams.exe
param 1 = Bed Bath \" Beyond
|
1. cmd.exe command line parser interprets ^" as an escaped " character so it does not start or end a double quoted part. The ^ is removed. The " is not removed.
2. The C/C++ command line parser receives this.
The C/C++ command line parser interprets the first " as “Start a double quoted part” and the double quote is removed.
The C/C++ command line parser interprets \\\" inside the double quoted part as a literal \"
The C/C++ command line parser interprets the ending " as “End the double quoted part” and the double quote is removed.
3. The C/C++ command line parser fills the argv[] array with the result.
| Parsing Example 8 |
1. ShowParams.exe ^"\^"Bed Bath Beyond\^"^"
└┘ └┘ └┘└┘
↓
↓ ┌───────────────────┐
↓ │ │
2. ↓ "\"Bed Bath Beyond\""
└┘ └┘
↓
↓ ↓
↓ ↓
↓
3. ↓ "Bed Bath Beyond"
↓ ↓
↓ ↓
↓ ↓
4. argv[0] argv[1]
param 0 = ShowParams.exe
param 1 = "Bed Bath Beyond"
|
1. cmd.exe command line parser interprets ^" as an escaped " character so it does not start or end a double quoted part. The ^ is removed. The " is not removed.
cmd.exe command line parser interprets \ as an ordinary character.
cmd.exe command line parser interprets ^" as an escaped " character so it does not start or end a double quoted part. The ^ is removed. The " is not removed.
cmd.exe command line parser interprets Bed Bath Beyond\ as ordinary characters.
cmd.exe command line parser interprets ^" as an escaped " character so it does not start or end a double quoted part. The ^ is removed. The " is not removed.
cmd.exe command line parser interprets ^" as an escaped " character so it does not start or end a double quoted part. The ^ is removed. The " is not removed.
2. The C/C++ command line parser receives this.
The C/C++ command line parser interprets the first " as “Start a double quoted part” and the double quote is removed.
The C/C++ command line parser interprets \" inside the double quoted part as a literal "
The C/C++ command line parser interprets \" inside the double quoted part as a literal "
The C/C++ command line parser interprets the ending " as “End the double quoted part” and the double quote is removed.
3. The C/C++ command line parser fills the argv[] array with the result.
8.1
How To Pass A Parameter to:
a C/C++ Program from the Command Line
A Simplified method: (new!2016) (updated 2019)
The trick is to enclose parameters with ^" instead of just "
e.g. instead of:
"Bed Bath Beyond"
use
^"Bed Bath Beyond^"
The command processor cmd.exe will strip off the ^ and won't start any double quoted parts.
Simplified method steps:
• Start with the parameter you want
- Search for any " (double quotes) which are a part of the parameter.
Double the number of \ immediately preceding any " (there may be none).
Then add one more \ before the "
i.e. to insert " use \"
to insert \" use \\\"
to insert \\" use \\\\\"
to insert \\\" use \\\\\\\"
- If the parameter ends in a trailing \
double the number of trailing \ (there may be none).
(2019: Thank you to Florian Balmer for noting this missing step.)
- Escape with ^ all these special characters: ^ < > | & ( ) "
i.e. replace ^ with ^^
replace < with ^<
replace > with ^>
replace | with ^|
replace & with ^&
replace ( with ^(
replace ) with ^)
replace " with ^"
- Add a leading and trailing ^"
Example 8.1: Command Line to C/C++ Program
Example 8.1: Bed Bath & Beyond |
Parameter |
| Start with the parameter you want (parameter includes spaces) |
Bed Bath & Beyond |
| 1. | Search for any " |
no " in parameter
|
| 2. | Escape with ^ all special characters: ^ < > | & ( ) "
i.e. replace ^ with ^^
replace < with ^<
replace > with ^>
replace | with ^|
replace & with ^&
replace ( with ^(
replace ) with ^)
replace " with ^"
|
Bed Bath ^& Beyond
↑
|
| 3. | double the number of trailing \ |
no trailing \
|
| 4. | Add a leading and trailing ^" |
^"Bed Bath ^& Beyond^"
↑↑ ↑↑
|
| 5. |
If this will be placed in a batch file, double the % characters |
no % in parameter |
Result: To get desired parameter use this: |
^"Bed Bath ^& Beyond^" |
| Now examine how this parameter gets parsed: |
| A. | cmd.exe treats ^ as escape character.
cmd.exe finds no double quoted parts because all " are escaped with ^
cmd.exe removes escape character ^ |
^"Bed Bath ^& Beyond^"
↓ ↓ ↓ |
| B. | cmd.exe passes this to the C/C++ program
|
"Bed Bath & Beyond" |
| C. | C/C++ program parses string starting at the beginning.
C/C++ program encounters initial " and starts a double quoted part. The " is removed.
|
┌──────
"Bed Bath & Beyond"
↓
|
| D. | C/C++ program copies characters to output parameter until it encounters closing "
The double quoted part ends and the " is removed.
|
┌─────────────────┐
Bed Bath & Beyond"
↓
|
| E. | C/C++ program encounters space (or end of string) after parameter.
Since we are no longer in a double quoted part, parser declares this is the end of the parameter.
|
┌─────────────────┐
Bed Bath & Beyond
↓
|
| F. | Result is the desired parameter we started with
|
Bed Bath & Beyond
|
Sample Test File:
Example 8.1b: Command Line to C/C++ Program
Example 8.1b: Bed Bath & Beyond\ |
Parameter |
| Start with the parameter you want (parameter includes spaces) |
Bed Bath & Beyond\ |
| 1. | Search for any " |
no " in parameter |
| 2. | Escape with ^ all special characters: ^ < > | & ( ) "
i.e. replace ^ with ^^
replace < with ^<
replace > with ^>
replace | with ^|
replace & with ^&
replace ( with ^(
replace ) with ^)
replace " with ^"
|
Bed Bath ^& Beyond\
↑
|
| 3. | double the number of trailing \ |
Bed Bath ^& Beyond\\
↑↑
|
| 4. | Add a leading and trailing ^" |
^"Bed Bath ^& Beyond\\^"
↑↑ ↑↑
|
| 5. |
If this will be placed in a batch file, double the % characters |
no % in parameter |
Result: To get desired parameter use this: |
^"Bed Bath ^& Beyond\\^" |
| Now examine how this parameter gets parsed: |
| A. | cmd.exe treats ^ as escape character and removes them.
cmd.exe finds no double quoted parts because all " are escaped with ^ |
^"Bed Bath & Beyond\\^"
↓ ↓ |
| B. | cmd.exe passes this as parameter to the C/C++ program
|
"Bed Bath & Beyond\\" |
| C. | C/C++ program sees the first double quote as beginning a double quoted part.
This double quote is not added to the parameter.
|
┌──────────────
Bed Bath & Beyond\\"
|
| D. | C/C++ program copies characters to the output parameter.
When it encounters the \ it finds two \ followed by a "
• Two is an even number
• We are currently in a double quoted part
• The character following the " is not another "
→ Therefore two/2=1 backslashes are added to the parameter
→ and the " ends the double quoted part
|
┌──────────────────┐
Bed Bath & Beyond\
↑
|
| E. | Result is the desired parameter we started with
|
Bed Bath & Beyond\
|
Sample Test File:
Now examine what would happen if we had only one backshash at the end instead of two:
A. cmd.exe treats ^ as escape character and removes them.
cmd.exe finds no double quoted parts because all " are escaped with ^
^"Bed Bath & Beyond\^"
↓ ↓
B. cmd.exe passes this as parameter to the C/C++ program
"Bed Bath & Beyond\"
C. C/C++ program sees the first double quote as beginning a double quoted part
┌──────────────
Bed Bath & Beyond\"
D. C/C++ program copies characters to the output parameter.
When it encounters the \ it finds one \ followed by a "
• One is an odd number
→ One/2=0 so no backslashes are added to the parameter
• We are currently in a double quoted part
→ Therefore the " is added to the parameter. The double quoted part continues.
┌────────────────────
Bed Bath & Beyond"
↑
E. If there was more following this it would be considered a part of the same parameter.
If the command line abruptly ends, the parameter is accepted as is,
even though the double quoted part wasn't closed properly.
Bed Bath & Beyond"
Example 8.1c: Command Line to C/C++ Program
Example 8.1c: Bed Bath \\\ Beyond |
Parameter |
| Start with the parameter you want (parameter includes spaces) |
Bed Bath \\\ Beyond |
| 1. | Search for any " |
no " in parameter |
| 2. | Escape with ^ all special characters: ^ < > | & ( ) "
i.e. replace ^ with ^^
replace < with ^<
replace > with ^>
replace | with ^|
replace & with ^&
replace ( with ^(
replace ) with ^)
replace " with ^"
|
no special characters in parameter
|
| 3. | double the number of trailing \ |
no trailing \
|
| 4. | Add a leading and trailing ^" |
^"Bed Bath \\\ Beyond^"
↑↑ ↑↑
|
| 5. |
If this will be placed in a batch file, double the % characters |
no % in parameter |
Result: To get desired parameter use this: |
^"Bed Bath \\\ Beyond^" |
| Now examine how this parameter gets parsed: |
| A. | cmd.exe treats ^ as escape character and removes them.
cmd.exe finds no double quoted parts because all " are escaped with ^ |
^"Bed Bath \\\ Beyond^"
↓ ↓ |
| B. | cmd.exe passes this as parameter to the C/C++ program
|
"Bed Bath \\\ Beyond" |
| C. | C/C++ program sees the first double quote as beginning a double quoted part.
This double quote is not added to the parameter.
|
┌────────
Bed Bath \\\ Beyond"
|
| D. | C/C++ program copies characters to the output parameter.
Parser comes to the \\\ followed by a space
→ Since \\\ is not followed by a " they are copied as is.
|
┌────────────
Bed Bath \\\ Beyond"
|
| E. | Parser comes to the "
→ We are in a double quoted part, so parser checks to see if
there's another " immediately following, which there is not,
so this " ends the double quoted part and the " is not added to the parameter.
|
┌───────────────────┐
Bed Bath \\\ Beyond"
↓
|
| E. | Result is the desired parameter we started with
|
Bed Bath \\\ Beyond
|
Sample Test File:
Example 8.2: Bed "Bath" & Beyond |
Parameter |
| Start with the parameter you want (parameter includes spaces) |
Bed "Bath" & Beyond |
| 1. | Search for any "
Double the number of \ immediately preceding any " (there are none)
Then add one more \ before each " |
Bed \"Bath\" & Beyond
↑ ↑
|
| 2. | Escape with ^ all special characters: ^ < > | & ( ) " |
i.e. replace ^ with ^^
replace < with ^<
replace > with ^>
replace | with ^|
replace & with ^&
replace ( with ^(
replace ) with ^)
replace " with ^"
|
Bed \^"Bath\^" ^& Beyond
↑ ↑ ↑
|
| 3. | double the number of trailing \ |
no trailing \
|
| 4. | Add a leading and trailing ^" |
^"Bed \^"Bath\^" ^& Beyond^"
↑↑ ↑↑
|
| 5. |
if this will be placed in a batch file, double the % characters |
no % in parameter |
Result: To get desired parameter use this: |
^"Bed \^"Bath\^" ^& Beyond^" |
| Now examine how this parameter gets parsed: |
| A. | cmd.exe treats ^ as escape character and removes them.
cmd.exe finds no double quoted parts because all " are escaped with ^
|
^"Bed \^"Bath\^" ^& Beyond^"
↓ ↓ ↓ ↓ ↓
|
| B. | cmd.exe passes this as parameter to the C/C++ program
|
"Bed \"Bath\" & Beyond" |
| C. | C/C++ program sees this as a double quoted parameter.
Note that all " inside the parameter are escaped with \
|
┌─────────────────────┐
"Bed \"Bath\" & Beyond"
↓ ↓
|
| D. | C/C++ program applies the rule 2n+1 backslashes followed by a "
produce n backslashes + a literal quotation mark.
\" becomes " (for n=0)
|
Bed \"Bath\" & Beyond
↓ ↓
|
| E. | Result is the desired parameter we started with
|
Bed "Bath" & Beyond
|
Sample Test File:
Example 8.3: Bed Bath & \"Beyond" |
Parameter |
| Start with the parameter you want (parameter includes spaces) |
Bed Bath & \"Beyond" |
| 1. | Search for any "
Double the number of \ immediately preceding any "
Then add one more \ before each " |
Bed Bath & \\\"Beyond\"
↑↑↑ ↑
|
| 2. | Escape with ^ all special characters: ^ < > | & ( ) " |
i.e. replace ^ with ^^
replace < with ^<
replace > with ^>
replace | with ^|
replace & with ^&
replace ( with ^(
replace ) with ^)
replace " with ^"
|
Bed Bath ^& \\\^"Beyond\^"
↑ ↑ ↑
|
| 3. | double the number of trailing \ |
no trailing \
|
| 4. | Add a leading and trailing ^" |
^"Bed Bath ^& \\\^"Beyond\^"^"
↑↑ ↑↑
|
| 5. |
if this will be placed in a batch file, double the % characters |
no % in parameter |
Result: To get desired parameter use this: |
^"Bed Bath ^& \\\^"Beyond\^"^" |
| Now examine how this parameter gets parsed: |
| A. | cmd.exe treats ^ as escape character and removes them.
cmd.exe finds no double quoted parts because all " are escaped with ^ |
^"Bed Bath ^& \\\^"Beyond\^"^"
↓ ↓ ↓ ↓ ↓ |
| B. | cmd.exe passes this as parameter to the C/C++ program
|
"Bed Bath & \\\"Beyond\"" |
| C. | C/C++ program sees this as a double quoted parameter.
Note that all " inside the parameter are escaped with \
|
┌───────────────────────┐
"Bed Bath & \\\"Beyond\""
↓ ↓
|
| D. | C/C++ program applies the rule 2n+1 backslashes followed by a "
produce n backslashes + a literal quotation mark
\\\" becomes \"
\" becomes "
|
Bed Bath & \\\"Beyond\"
---- --
|
| E. | Result is the desired parameter we started with
|
Bed Bath & \"Beyond"
|
Sample Test File:
Example 8.4: (Bed) <Bath> & "Beyond" | \"Kohl^s |
Parameter |
| Start with the parameter you want (parameter includes spaces) |
(Bed) <Bath> & "Beyond" | \"Kohl^s |
| 1. | Search for any "
Double the number of \ immediately preceding any "
Then add one more \ before each " |
(Bed) <Bath> & \"Beyond\" | \\\"Kohl^s
↑ ↑ ↑↑↑
|
| 2. | Escape with ^ all special characters: ^ < > | & ( ) " |
i.e. replace ^ with ^^
replace < with ^<
replace > with ^>
replace | with ^|
replace & with ^&
replace ( with ^(
replace ) with ^)
replace " with ^"
|
^(Bed^) ^<Bath^> ^& \^"Beyond\^" ^| \\\^"Kohl^^s
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
|
| 3. | double the number of trailing \ |
no trailing \
|
| 4. | Add a leading and trailing ^" |
^"^(Bed^) ^<Bath^> ^& \^"Beyond\^" ^| \\\^"Kohl^^s^"
↑↑ ↑↑
|
| 5. |
if this will be placed in a batch file, double the % characters |
no % in parameter |
Result: To get desired parameter use this: |
^"^(Bed^) ^<Bath^> ^& \^"Beyond\^" ^| \\\^"Kohl^^s^" |
| Now examine how this parameter gets parsed: |
| A. | cmd.exe treats ^ as escape character and removes them.
cmd.exe finds no double quoted parts because all " are escaped with ^ |
^"^(Bed^) ^<Bath^> ^& \^"Beyond\^" ^| \\\^"Kohl^^s^"
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ |
| B. | cmd.exe passes this as parameter to the C/C++ program
|
"(Bed) <Bath> & \"Beyond\" | \\\"Kohl^s" |
| C. | C/C++ program sees this as a double quoted parameter.
Note all " inside the double quoted parameter are escaped with \
|
┌──────────────────────────────────────┐
"(Bed) <Bath> & \"Beyond\" | \\\"Kohl^s"
↓ ↓
|
| D. | C/C++ program applies the rule 2n+1 backslashes followed by a "
produce n backslashes + a literal quotation mark
\" becomes "
\\\" becomes \"
|
(Bed) <Bath> & \"Beyond\" | \\\"Kohl^s
-- -- ----
|
| E. | Result is the desired parameter we started with
|
(Bed) <Bath> & "Beyond" | \"Kohl^s
|
Sample Test File:
Example 8.5: &<>^|()@!" |
Parameter |
Start with the parameter you want (parameter includes a space) |
&<>^|()@!" |
| 1. | Search for any "
Double the number of \ immediately preceding any "
Then add one more \ before each " |
&<>^|()@!\"
↑
|
| 2. | Escape with ^ all special characters: ^ < >| & ( ) " |
i.e. replace ^ with ^^
replace < with ^<
replace > with ^>
replace | with ^|
replace & with ^&
replace ( with ^(
replace ) with ^)
replace " with ^"
|
^&^<^>^^^|^(^)^@^!\^"
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
|
| 3. | double the number of trailing \ |
no trailing \
|
| 4. | Add a leading and trailing ^" |
^"^&^<^>^^^|^(^)^@^!\^"^"
↑↑ ↑↑
|
| 5. |
if this will be placed in a batch file, double the % characters |
no % in parameter |
Result: To get desired parameter use this: |
^"^&^<^>^^^|^(^)^@^!\^"^"
|
| Now examine how this parameter gets parsed: |
| A. | cmd.exe treats ^ as escape character and removes them.
cmd.exe finds no double quoted parts because all " are escaped with ^ |
^"^&^<^>^^^|^(^)^@^!\^"^"
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
|
| B. | cmd.exe passes this as parameter to the C/C++ program
|
"&<>^|()@!\"" |
| C. | C/C++ program sees this as a double quoted parameter.
Note all " inside the double quoted parameter are escaped with \
|
┌───────────┐
"&<>^|()@!\""
↓ ↓
|
| D. | C/C++ program applies the rule 2n+1 backslashes followed by a "
produce n backslashes + a literal quotation mark
\" becomes "
|
&<>^|()@!\"
--
|
| E. | Result is the desired parameter we started with
|
&<>^|()@!"
|
Sample Test File:
The following older examples show the harder way of figuring out what to use as parameters.
(Note there are multiple ways of achieving the same result.)
Example 8.6: Command Line to C/C++ Program
Example 8.6a: &<>^|()@ ! |
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.6b: &<>^|()@ ! |
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.7: Command Line to C/C++ Program
Example 8.7: &<>^|@()!"&<>^|@() ! |
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.8: Command Line to C/C++ Program
Example 8.8a: &<>^|@() !"&<>^|@() ! |
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.8b: &<>^|@() !"&<>^|@() ! |
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.9: Command Line to C/C++ Program
Example 8.9a: "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.9b: "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.10: Command Line to C/C++ Program
Example 8.10a: "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.10b: "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:
- TestParams8_10.bat
- REM all 4 lines should produce the same result
ShowParams.exe "\"C:\TEST ^%%^&^^ A\\\""
ShowParams.exe ^"\^"C:\TEST %%^&^^ A\\\^"^"
ShowParams.exe "\"C:\TEST ^%%^&^^ A\\\""
ShowParams.exe \^"C:\TEST^" ^"%%^&^^^" ^"A\\\^"
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:
- The cmd.exe command line parser parses your command line & parameters and then starts running the batch file
- The batch file retrieves the parameters, but when you use them, they get parsed again. Here's an example:
- a batch file line contains %1
- %1 is replaced with your parameter
- that line is then sent to the command line parser for execution, where it gets parsed
Overview of steps:
- Start with the parameter you want
- Apply the command line parsing rules that cmd.exe will apply when you enter the command and parameters [sec. 7]
- 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:
- Apply the Command Line Parser (cmd.exe) parsing rules
- determine what cmd.exe will see as the quoted parts
- escape the special characters < > | & ^ not in a double quoted part
- 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
- 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:
- Use ^^^ outside double quotes to escape < > & | ^
to insert < use ^^^<
to insert > use ^^^>
to insert | use ^^^|
to insert ^ use ^^^^
- Sometimes it may be necessary to also escape ( ) @ !
- It's OK to escape everything
- Note ^ is also the line continuation character.
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.)
- Command line arguments can be separated by an unquoted semicolon or comma. This affects builtin commands like COPY and batch file parameters.
- 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:
- TestParams9_1.bat
- ShowParams.bat ^^^&^^^<^^^>^^^^^^^|()@!
(Note: Since this is a batch file,
if there were any % we would need to double them.
WARNING! When executing a batch file from inside another batch file, the original batch file is terminated before the other one starts. This method of invoking a batch file from another is usually referred to as chaining.)
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:
- TestParams9_2.bat
- ShowParams.bat "&<>^|()@!"
(Note: Since this is a batch file,
if there were any % we would need to double them.
WARNING! When executing a batch file from inside another batch file, the original batch file is terminated before the other one starts. This method of invoking a batch file from another is usually referred to as chaining.)
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
- TestParams9_3a.bat
- ShowParams.bat "&<>^|()@!"^^^&^^^<^^^>^^^^^^^|()@!^^^"
(Note: Since this is a batch file,
if there were any % we would need to double them.
WARNING! When executing a batch file from inside another batch file, the original batch file is terminated before the other one starts. This method of invoking a batch file from another is usually referred to as chaining.)
- TestParams9_3b.bat
- ShowParams.bat "&<>^|()@!"^^^&^^^<^^^>^^^^^^^|^^^(^^^)^^^@^^^!^^^"
(Note: Since this is a batch file,
if there were any % we would need to double them.
WARNING! When executing a batch file from inside another batch file, the original batch file is terminated before the other one starts. This method of invoking a batch file from another is usually referred to as chaining.)
- TestParams9_3c.bat
- ShowParams.bat "&<>^|()@!\"&<>^|()@!"
(Note: Since this is a batch file,
if there were any % we would need to double them.
WARNING! When executing a batch file from inside another batch file, the original batch file is terminated before the other one starts. This method of invoking a batch file from another is usually referred to as chaining.)
- TestParams9_3d.bat
- ShowParams.bat ^^^"^^^&^^^<^^^>^^^^^^^|()@!^^^"^^^&^^^<^^^>^^^^^^^|()@!^^^"
(Note: Since this is a batch file,
if there were any % we would need to double them.
WARNING! When executing a batch file from inside another batch file, the original batch file is terminated before the other one starts. This method of invoking a batch file from another is usually referred to as chaining.)
- TestParams9_3e.bat
- ShowParams.bat ^^^"^^^&^^^<^^^>^^^^^^^|^^^(^^^)^^^@^^^!^^^"^^^&^^^<^^^>^^^^^^^|^^^(^^^)^^^@^^^!^^^"
(Note: Since this is a batch file,
if there were any % we would need to double them.
WARNING! When executing a batch file from inside another batch file, the original batch file is terminated before the other one starts. This method of invoking a batch file from another is usually referred to as chaining.)
10.
How To Pass A Parameter to:
a VBScript, JScript, or WSH Script
from the Command Line
VBScript (.vbs), JScript
9 (.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
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:
- parameters are separated by a space or tab (multiple spaces/tabs OK)
- " begins and ends the double quoted part)
- all characters within a double quoted part are accepted, including spaces and tabs)
- The " character itself is always stripped from the parameter)
(Note this means you can not pass a double quote as part of a parameter.))
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:
- call Kernel32.dll!GetCommandLine() to get the command line
- make a copy of the command line
- call wscript!SplitCommandLine() dry run to determine the number of parameters
- allocate space for argv[] array
- 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:
- " flag - set if we're currently inside a double quoted part
- The algorithm only looks for {space}, {tab}, and ("). All other characters are just characters.
- You can't pass a double quote (") as part of a parameter because double quotes are always stripped off.
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:
- 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.
- 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:
- Start with the parameter you want
- Apply the WSH parsing rules that Windows Script Host will apply when parsing the command line it retrieves
- 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:
- Apply the WSH parsing rules:
- 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
- Apply the Command Line Parser (cmd.exe) parsing rules
- determine what cmd.exe will see as the double quoted parts
- 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
- If your command line will be placed in a batch file, double the % character11
10.4 Sample Scripts:
Sample 'Show Parameters' scripts:
VBScript:
- ShowParams.vbs
- If Wscript.Arguments.Count = 0 Then
Wscript.echo "No parameters found"
Else
i=0
Do until i = Wscript.Arguments.Count
Parms = Parms & "Param " & i & " = " & Wscript.Arguments(i) & " " & vbcr
i = i+1
loop
Wscript.echo parms
End If
JScript:
- ShowParams.js
- if (WScript.Arguments.Count() ==0) {
WScript.Echo("No parameters found");
}
else {
var objArgs = WScript.Arguments;
var parms = ""
for (i=0, n=objArgs.length; i<n; i++) {
parms += '\nParam '+i+'='+objArgs(i);
}
WScript.Echo(parms);
}
11.
How To Pass A Parameter to
a Perl script from the command line
ActivePerl
12 and Strawberry Perl
13 both call
MSVCRT.dll!__getmainargs
which follows the Microsoft C/C++ Parameter Parsing Rules.
Therefore the steps are:
- Start with the parameter you want
- Apply the Microsoft C/C++ parsing rules that ShowParams.exe will apply when parsing the command line it retrieves [sec. 5]
- 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:
- ShowParams.pl
- if ( $#ARGV < 0 ) {
print "No parameters\n";
}
else {
my $i = 0;
my $Parms = "";
while ( $i <= $#ARGV ) {
$Parms .= "Param $i = $ARGV[$i]\n";
$i ++;
}
print $Parms;
}
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:
- Start with the parameter you want
- Apply the Microsoft C/C++ parsing rules that ShowParams.exe will apply when parsing the command line it retrieves [sec. 5]
- 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:
- ShowParams2.py
- #!/usr/bin/python
# Filename: using_sys.py
import sys
print 'The command line arguments are:'
for i in sys.argv:
print i
print '\n\nThe PYTHONPATH is', sys.path, '\n'
Sample 'Show Parameters' Python script for Python version 3:
- ShowParams3.py
- #!/usr/bin/python
# Filename: using_sys.py
import sys
print( 'The command line arguments are:' )
for i in sys.argv:
print( i )
print( '\n\nThe PYTHONPATH is', sys.path, '\n' )
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:
- ShowParams.rex
- NumParams = %0%
Param1 = %1%
Param2 = %2%
Param3 = %3%
MsgBox GetCommandLine=%string%`nNumParams = %0%`nParam1 = %1%`nParam2 = %2%`nParam3 = %3%
ExitApp
14.
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:
- ShowParams.rb
- ARGV.each do|a|
puts "Argument: #{a}"
end
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:
- Start with the parameter you want
- Apply the Microsoft C/C++ parsing rules that ShowParams.exe will apply when parsing the command line it retrieves [sec. 5]
- 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:
- ShowParams.ahk
-
NumParams = %0%
Param1 = %1%
Param2 = %2%
Param3 = %3%
result := DllCall("kernel32\GetCommandLineW")
pointer := result
string := DllCall("MulDiv","int",pointer,"int",1,"int",1,"str")
MsgBox GetCommandLine=%string%`nNumParams = %0%`nParam1 = %1%`nParam2 = %2%`nParam3 = %3%
ExitApp
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
Thank you to Delan Azabani for the following explanation:
Technically, execl(3) and friends
do not allow you to specify a command line string [i],
but rather a sequence of previously separated arguments via variadic C arguments.
execv(3) and friends are similar, except that they use decayed arrays.
The complete exec family includes exec{l,le,lp,v,ve,vp}, fexecve(3),
and if you’re using glibc, the execvpe(3) extension.
The family may be invoked in a way that allows you to specify a
command line string — including, for example, together with sh(1):
execl("/path/to/bin/sh", "sh", "-c", command_line, (char *) NULL);
This is roughly how system(3) is specified by POSIX [ii].
[i] http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html
[ii] http://pubs.opengroup.org/onlinepubs/9699919799/functions/system.html
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").
9.
JScript is Microsoft's own version of JavaScript.
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.
19.
Thanks to András Korn for assistance in updating the *nix section (Feb. 2011).
David Deley © 2009
http://daviddeley.com
Last update: July 5, 2020
Thank you to Stefan Kanthak for pointing out some spelling errors.