Creating subroutines in batch files is easy. Just create a label, a goto :EOF and call :label. However, if the subroutine uses a setlocal-endlocal block you might want to be able to pass variable changes out of that block and still retain the local scope to avoid pollution of the upper scope.
You can exploit the fact that cmd expands variables on reading a line before actually executing it:
The trick here is that variable expansion takes place before endlocal (or the set following it) is executed and set is executed after endlocal and thus affects the outer scope, but is able to pass a value of the inner scope along.
Note: I've seen this trick before at Paul Sadowski's site and found it worth remembering, although I didn't use it that much so far (my Bignum implementation will, however make extensive use if it).
Arrays are frequently used in programming and nearly all programming languages have something that can be used as such, nevermind what it's called. Arrays, tables, lists, etc. are all just a means of organizing large amounts of similar data.
In batch files we have to do a little trickery to achieve something one might call arrays. There are at least two possibilities that spring to my mind instantly:
The easiest and most flexible solution I've come up with so far is simply to create a variable for each entry, all of them share a common prefix (which may be empty). So, to create an array with, say, 100 members, this can be done quickly with
for /l %%i in (1, 1, 100) do set ARRAY%i=0
That way we have an array, called ARRAY (the prefix, I usually use it as a name) with 100 variables in it, each initialized to 0.
Array access is simple in just accessing the appropriate variable, it has, however, a few issues:
echo %ARRAY2%
echo !ARRAY%NUM%!
for /l %%i in (3, 1, 5) do echo !ARRAY%%i!%ARRAY%NUM%% won't work since cmd's parser gets confused with the %. And % variables will be expanded when the line is read, not when it's executed.
set /a SUM=ARRAY%X%+ARRAY%Y%If you insist, you can also use a notation familiar with other programming languages, [ and ] are perfectly legal as characters in environment variables (if I remember correctly the only illegal characters are = and the null byte).
If you know which characters your array variables will contain you can also use a long string with a separator character:
set ARRAY=1,2,3,4,5,6,7,8,9,10
This requires you to use for /f whenever you need to access a value within the array, write-access to values is very inconvenient (essentially you have to either search for the right indices within the string and do substring magic or you rebuild the entire array each time you change or delete a value.
To sum it up: I always used the first variant, since it's pretty easy and depending on your application deleting values (and tedious copying) might not be necessary or even wanted (my Sieve of Eratosthenes simply kept only the values it was interested in and used if defined to check for them.
A common task in many algorithms is swapping two values. Usually implentations take the form
temp := a;
a := b;
b := temp;
In some languages (such as Python or Lua) you may also write the following:
a, b = b, a
And a method similar to this one is even possible in batch files.
Since variable substitution in CMD is done while the line is parsed (for backwards compatibility) except when using ! instead of % we can use this to our advantage and swap to values in one line without resorting to a temporary variable:
set A=%B%&set B=%A%
Be careful not to use a space before the & to avoid having that space character in your value (if this is critical).
And the use of % here is also important. Since delayed expansion (done with ! expands when the value is used the code set A=!B!&set B=!A! will set both A and B to the value of B.
If there is one thing the Windows Command Processor (cmd.exe) can do (except starting other programs) it's string processing. Not at Perl's level but certainly more sohpisticated than the C standard library (not counting regex here).
I was just playing around a bit and came up with this:
setlocal with the usual options (I almost always set them, regardless whether I need them or not). Saving all command line arguments into a string and then dissecting it character by character. As soon as the original string is eaten up we can quit and output the result.
And it works in Unicode, too:
When writing a loop sometimes it can become necessary to break out of the loop before it is finished. Batch files allow loops, but do they allow some kind of break statement?
Actually, yes:
if statement checks for the loop variable being greater than 10 and based on that will either break or print the number. And as you can see, if we would let the loop finish we wouldn't see any message since we quit immediately after the loop.
Does this work with subroutines as well? Sure:
goto :EOF), so when branching out of the subroutine we would print "successfully broken the loop" but return to looping directly thereafter.
Well, starting from “Or” considered harmful. we noticed that the distinction of andor, xor and ewok is certainly a useful concept, however, the naming scheme leaves room for improvement. Andor is certainly too long for practical usage and ewok always raises associations to small furry creatures.
On the quest for appropriate names we thought that or certainly suffices for andor, just like (mathematical) logic tells us. Xor is short and pronounceable enough for everyday use and the meaning is clear with the usual knowledge of geeks. This leaves ewok. sh suggested eor, which may be interpreted as ewok-or. It does not sound too stupid, is short enough and thus quite usable.
The only challenge now is to switch my writing and talking habits over to those new words :-)
Ever wondered which exact executable will be executed when running a command from the command line? UNIXes and Linux have which(1) which tells that. There are implementations on Windows, but not one in batch language I was aware of :-)
So that naturally called for ugly things to be done. I wrote this a while ago and noticed that it does not always works correctly on Windows Vista. At the time of its writing I was working with Windows 2000 and it worked pretty well there. Somehow something is messing with extensions:UPDATE (2008–06–01): I found another bug that manifests itself most prominently on Windows Vista x64, concerning paths with closing parentheses in them (as happens when installing x86 applications there). That means I have to do a bit escaping as soon as those paths show up in the argument of a FOR loop. Using ! and FOR /F seems to work somehow, except that I only get a single token from that.
A while ago a fellow student of mine held a “lecture” for pupils on programming where I should help helping the kids. Prime numbers are a nice topic for introductory courses, since they are easy to understand and a simple search for them is written in a few lines of code. I suggested mentioning the Sieve of Eratosthenes as well as giving an implementation of it, since I think the algorithm is pretty easy to understand and nicely fast in generating the first n primes. The programming language we used was Pascal and I was able to come up with a naïve implementation in a manner of minutes. Glancing over the program again I thought it wouldn't be that hard to implement in CMD, so I tried … there was still plenty of time left so I wrote the following perversion of batch language :-)
It's actually very short and I was surprised that it took only that few lines to write. We start by allocating a bunch of n boolean array elements:There is a practical limit for n, though. The batch runs fine for 100 or even 1000 numbers, but sieving 20000 numbers already takes about a minute on my notebook. And there was a point at which the environment seemed to grow too large to handle in a sensible way.
And no, it does not compute all this in parallel, though I wonder how hard it would be to create batch files that calculate things concurrently in multiple processes; might actually make use of all those multicore systems out there. But I don't have a good idea currently how they should communicate if need arises; files are an option but slow and subject to races … well, I still have a lot of lectures I only attend physically, so my mind may be free to solve these problems :-)
This innocent batch file sports a finite state machine for parsing the parameters which may be given by the following regular expression:
I allow both German and English notation (w vs. d as separator of number and sides of the dice) as well as optional adding of all rolls and a constant (for Shadowrun 3 initiative rolls). Due to the nature of parsing the user will get pretty precise feedback where a parsing error occurred and what was expected (Hmm, this may call for a general batch FSM generation tool :).
A few limitations, however:
The code is nearly undocumented, but that just adds to the fun :-)
I faintly remember the times when games and other software came along with installation instructions (nowadays it seems most publishers assume that people can install software without instructing them). A common and recurring template was “Insert the CD into your CD ROM drive. The setup program should start automatically, if it doesn’t, follow these steps to turn on AutoPlay and try again: …”
This is, essentially, a non-solution. It solves a problem the customer doesn’t even have: Usually you don’t think ‘How could I turn on AutoPlay which I disabled a few weeks ago to save me from setups popping up?’ instead you want to run the setup that simply didn’t start automatically (which may be on purpose).
A similar situation occurred to me recently when I visited a web page that wanted to display an image in a popup. I have set my popup blocker to highly aggressive, so it blocks essentially everything that opens a new window. When I manually opened the link that caused the blocked popup in a new tab (a method that usually yields the content) I found myself on a page that explained in detail how I could either turn on Javascript or turn off my popup blocker.
Great. They are solving a problem I don’t even have. I just want to access the content.
Since the advent of popup blockers I doubt popups are a valid method of conveying information to the user anymore.