🪟❗wshbang [Source code available in GitHub].

Look everyone, it's the wshbear!

#! Support for Windows

A tool to support *nix-like #! functionality in Windows. This way, a file’s content determines the interpreter used, rather than its extension. In particular, it properly passes command-line arguments passed to your script & can be used with standard I/O | pipelines.

How it do?

It’s just a batch script that determines & invokes the target interpreter.

The other important detail is properly passing arguments from the command-line. That %* does some heavy lifting, yo. Unfortunately, it’s often overlooked. Worse, the Windows shell environment specifically removes it in some cases. Rude! Basically this puts it back.

It can be used explicitly to process a script

wshbang.bat my_script.py %a% %b% %c%

but more importantly allows direct calls

my_script.py %a% %b% %c%

Doing so still relies on Windows’s standard filetype/extension associations, but it turns out that is more involved than one might expect…

Setting default associations

Recent versions of Windows restrict how associations are set; older versions allow for programatic access – allowing 🪟❗ to do so itself.

Windows 10ish & up

The easiest way to handle this is probably via the usual right-click → Open with > menu, then associating wshbang.bat as the default by checking the “Always use…” box. Alternatively, the Default apps settings page can be used.

See the note below about arguments & first-time runs!

Windows 9 & other versions that don’t exist or earlier

Earlier versions of Windows can use the ftype & assoc internal commands to set associations from an elevated command prompt. wshbang can handle this for you automatically with the use of the -a argument. This will attempt to spawn a seperate, elevated prompt to do so – including a potential UAC confirmation.

Notably, elevation involves a round-trip through Powershell back into cmd.exe. Have a look if you want a janky sudo mimic. I need to come up with another tool for this legend.

Specifying a target interpreter

How do it know?

Well first of all, now you can just use a Windows path right in the file, if you don’t care about interoperability. It just runs that if a file is found there.

Really though chances are your script points to an interpreter via a Unix-style path. If you’re slick and use env to path-search, 🪟❗ will do the same. You don’t even need to add .exe or whatever. %PATH% & %PATHEXT% sexiness! Otherwise it prompts you to give it a path to your executable-of-choice; From then on it maps that *nix path to your interpreter. Note the use of con in the prompt code forces this to be interactive – this is deliberate to avoid devouring any standard input.

Where did my args go‽

Teal deer! I'm so funny Run it again.

This is a known limitation imposed by the Windows shell environment. Setting a file association will remove the %* from the command responsible for passing arguments. 🪟❗ adds it back every time it is run, but the unfortunate truth is the arguments have already been dropped by then. This can be confirmed, for example, by adding

echo %cmdcmdline%

somewhere in the script. The good news is because the script corrects this each time it runs, subsequent runs should work until you do something that drops the %* again, like using the “Open with…” prompt again. If need be to avoid running even once without arguments, first set the association via the settings, then invoke wshbang.bat once before running your script for realsies:

wshbang.bat > nul
this_time_for_realsies.py %a% %b% %c%

Other questions

  • Is this really that critical?
    • No, but I needed it for work some time ago so I could use code already written for a specific Linux environment without maintaining each script specifically. Once I did the actual work figuring out the details I figured I might as well just clean it up and make a public version.
  • A batch script? Really?
    • Well, I’d love to see a binfmt_misc-type kernel solution but that ain’t happening. Beyond that I figured a script is just transparent – don’t trust me, you see what you’re running before you do. At that point Batch is just the only “universal” option; I don’t know what people have going on with Windows Scripting Host, & Powershell script execution isn’t always permitted.
      Anyway, now you know how it works; it’d be easy to port to whatever you want.
  • What’s with all that chcp stuff at the beginning & end?
    • That changes the codepage to support Unicode & back if it was something else previously (it was). Basically that’s what lets it print happy little 🦝s.
  • Yea… what’s with the raccoons?
    • Raccoons are awesome! Also, they’re called washbears auf Deutsch.
      wshbang… wshbear. You get it.

Oh hi