Four years ago I blogged about an incantation that would allow the Windows command interpreter (cmd) to execute Unix shell scripts written inside plain batch files. Time for an update.
The original trick I posted involved starting the shell script with the line
@#!sh %0.bat %* 2>nul
However release 1.7 of Cygwin
no longer supports DOS device names
(such as NUL, PRN, CON), and therefore when the file is executed
under the Unix shell the redirection creates a file named nul.
Here is the rationale behind the year 2010 incantation update.
What we need in order to have a Windows command interpreter batch file (a file with a .BAT suffix) executed through the Unix shell is a Windows command that pass the file as an argument to the Unix shell. The following code will do this trick for its first argument.
@echo off
if "%~$PATH:1"=="" (
rem Not found in PATH; try to run it as specified using the current
rem directory or an absolute path
sh %1 %2 %3 %4 %5 %6 %7 %8 %9
) else (
rem Run the script from the path
sh %~$PATH:1 %2 %3 %4 %5 %6 %7 %8 %9
)
We then need a polyglot command to invoke the above code: a line that will be valid both in the Windows command interpreter and the Unix shell, because both will execute our file's first line. A polyglot program is one that is simultaneously valid in more than one programming language. Such programs have a long history as interesting curiosities. For instance, the following code by Jack Applin, which won in the 1986 International Obfuscated C Code Contest, is portable to the C and Fortran 77 compilers as well as executable by the Unix Bourne shell.
cat =13 /*/ >/dev/null 2>&1; echo "Hello, world!"; exit
*
* This program works under cc, f77, and /bin/sh.
*
*/; main() {
write(
cat-~-cat
/*,'(
*/
,"Hello, world!"
,
cat); putchar(~-~-~-cat); } /*
,)')
end
*/
A more recent example
is valid COBOL, Pascal, Fortran, C, Postscript, Unix shell, and machine code!
In our case starting a batch / shell script file with the following polyglot line does the trick.
@#!sh %0.bat %*
For the system to work we must also create in our path the following two files.
#!sh.bat
with
these contents.
(Download the file by right-clicking on the link;
note that the file name starts with #!
).
@#!sh
.#!sh.bat
passing to it as an argument
the location of the script and the remaining arguments.
When the Unix shell reads the line, it will invoke the command
@#!sh
, which, as an empty file, does nothing.
The rest of the file will then be executed as a shell script.
Because Windows batch files don't nest the batch file
#!sh.bat
will never return to execute the rest of the shell
script.
Comments
Post
Toot!
Tweet
Last modified: Tuesday, January 12, 2010 6:52 pm
Unless otherwise expressly stated, all original material on this page created by Diomidis Spinellis is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.