Javascript in the commandline

I don’t know for how long a little script has been running on my computer to keep me sane in the Windows driveletter jungle.

These days I work almost exclusively on Windows because frankly it fits my daily usage patterns best… that doesn’t mean it’s a perfect fit, but with a combination of Cygwin and a few dozens other tools as well as a Linux-like directory setup I can retain at least most of my sanity.

One very important tool in the way I organize my system are symlinks or more specifically junctions (they provide roughly the same functionality as Windows symlinks, but Windows doesn’t try to translate them to their target path when an application requests something inside).

For example if you want to find one of my external harddisks you’ll find it under \media\WD2000 which is a junction pointing to the drive’s root folder.

Theoretically you can do this without any junctions by setting that drive as a virtual folder. Problem is: Windows gets confused if you regularly change your external drives. Even more so if TrueCrypt is involved.

So I decided to use the junctions approach and write a little shell script to update the junctions automatically. FSUtil provides all the needed functionality, so it seemed simple enough. At least until I tried to do the necessary string processing using the Windows shell. Urgh. In short: Don’t even try. Whatever you try to do, it won’t work.

Luckily I had a Spidermonkey build at hand (js.exe) and while the Spidermonkey JS shell isn’t intended for shell scripting, it can handle STDIN and STDOUT which is really all you need. js.exe is now also part of XULRunner builds, so you can easily grab it from ftp://ftp.mozilla.org/pub/xulrunner/nightly/

Yes, I could have used dozens of other solutions. SED, WScript: but all of them would have required me to learn their syntax when I didn’t really want to. I just wanted to do string processing and I kinda felt that if I knew probably the best-known language for string processing, I shouldn’t have to learn another one for the same purpose.

What you do if you want to use JS for string processing, is make it part of a pipe chain, like this:

js -e “main=’f1′;” %0|cmd /K|js -e “main=’f2′;” %0|cmd /K

That looks worse than it actually is, it just means:
run js.exe (with main set to f1 and the cmd file loaded as js) output through cmd.exe
send cmd.exe output to js.exe (with main set to f2 and the cmd file loaded as js)
run js.exe (with main set to f2 and the cmd file loaded as js) output through cmd.exe

…you get the idea: You just alternate between js.exe and cmd.exe, each operating on the previous one’s output.

The only real pitfall is that your cmd file is both a cmd file and a js file at the same time, but that’s pretty easy to overcome:

REM = 0; /*
@echo off
cls
[[SHELL_CODE]]
goto :END
REM ; */
[[JS_CODE]]
REM ; /*
:END
REM ; */

Again: it looks worse than it is: You simply use JS comments to make js.exe ignore the shell code (you need a few dummy REM statements as well), while using a mixture of Shell comments and jump statements to make cmd.exe skip over the JS code.

And that’s pretty much it. Other then that you only really need to know that in order to read something from STDIN with js.exe you call readline() until it returns null and print(“foo”) to output “foo\n” (including a newline character).

Throw in something like this and you can call different functions directly;

var lines=[];
var line;
while(null!=(line=readline())) lines.push(line);
this[main](lines);

with
js -e “main='[[function name]]’;” %0

And finally, here’s the script file that I’m using to keep my junctions up to date:
http://www.tapper-ware.net/devel/js/js.shellJunctionUpdates/readyDriveList.js.cmd
It basically checks for a file \.mountpoint on every drive and creates a junction to that drive in the location specified inside the .mountpoint file (liek this: MOUNTPOINT=C:\media\WD2000)

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.