Nobody actually enjoys batch programming,
but sometimes you can get away with writing in a language
you like better while retaining the
Still, that leaves you having to get the extension for that
language registered on your target machines,
which can be tricky for xcopy-style deployment scenarios.
The solution then is to use a
header that is valid both as a batch file and in your target
The header re-invokes the target language interpreter
with the batch file itself as input.
Note: That this trick isn't necessary if you can associate
the file extension with the scripting engine.
So you don't need to do this polyglot nonsense with,
say, PowerShell scripts, because the
extension is already associated with
The general shape of a polyglot header is
@rem prefix stuff @〈interpreter〉.exe 〈interpreter options〉 "%~f0" %* @goto :eof 〈suffix stuff〉 〈the script itself〉 〈trail stuff〉
Prefixing each line with an at-sign prevents it from being echoed.
The first line is a comment, which lets you stick arbitrary goop
in front, in order to swallow up the
and make the rest of the header invisible to the interpreter.
"%~f0" %* sequence looks like line noise,
but it's actually a batch file idiom for
"A quoted, fully-qualified path to the batch file,
followed by the original arguments."
to build up a full path to the
%0 (which is the
batch file itself).
%* is a batch variable that expands to the
arguments passed to the batch file.
Anything after the
@goto :eof is ignored by the
so you can add language-specific suffix stuff to finish up the
"start ignoring this" goop you set up on the first line.
Finally, in rare cases, you might need to add trail stuff at the end of the script to balance out anything you set up in the header, like closing an open set of braces. This is rare because you usually close them up in the 〈suffix stuff〉 part.
Okay, now that we see the general shape of a polyglot header, let's look at some examples.
@rem --*-Perl-*-- @perl.exe -x "%~f0" %* goto :eof #!perl 〈perl script〉
This isn't a proper polyglot because we're running perl
in a special mode which is not the default (
we're trying to get things done, not solve some theoretical puzzle,
so running perl in a special mode is just fine if it gets the job done.
Note that if you want other special command line options to be passed
to perl, you can sneak them in with the
For example, you might ask for
-Sx to get poor-man's
command line switch auto-parsing.
The leading comment
--*-Perl-*-- is not used by either
perl or the command processor.
It's there by tradition,
so that when emacs users load the script into the editor,
it will be detected as a perl script,
and perl-specific editing commands will be enabled.
@if (1 == 0) @end /* @cscript.exe /E:jscript /nologo "%~f0" %* goto :eof */ 〈JScript script〉
Instead of using
the JScript polyglot header uses an
that is never true.
This was chosen so that the opening syntax of the file matches
JScript conditional compilation,
and the entire header gets gobbled up as
a false conditional followed by a big comment.
Note that JScript conditional compilation is a Microsoft extension,
cscript runs the Microsoft JScript engine
when you specify
it's okay to use it anyway.
Sometimes I miss the
OS/2's command interpreter,
then I realize that it really only solves half of the problem
(getting the command interpreter to hand control to another
and doesn't solve the other half
(getting the scripting engine to ignore the start of the batch file).
The additional restriction that
EXTPROC appear on the
first line of the batch file makes it harder to work the first line
into valid code in your target language.
Bonus chatter 2:
JScript is probably the most convenient alternative scripting
language because, while it may be
the world's most misunderstood programming language,
it's nevertheless immeasurably better than batch.
And it has come preinstalled since Windows 2000,
so your script will work on pretty much any Windows computer of
The downside is that the version of JScript used by
PowerShell is very nice, but it wasn't standard-issue until Windows 7. With the retirement of Windows Vista, we are finally in a situation where all supported versions of Windows come with PowerShell. It took eight years, but we made it. (Note that you can't run PowerShell scripts by default. You have to go in and change an administrative setting first.)
So maybe, if you're lucky, you may be able to declare the end of the era of suffering with batch files. I can more confidently say that the suffering of Batch File Week is now over, at least for now.
Bonus content: Here'a Web page which demonstrates various batch file string manipulation operations.