100 Languages Speedrun: Episode 72: Windows Batch Files
Tags: dos, windows
Published: 2022-01-28 23:39:13

Batch Files, with extension `.bat`, were DOS equivalent of shell scripts.

DOS version (still used by DOSBox) was extremely limited, and couldn't even add numbers. Starting with OS/2 and Windows NT, `.bat` files were extended with some very rudimentary scripting capabilities, so that's what we'll be doing today, but I'll limit my use of these extended features to just `set /a` for math.

You can run these examples on any Windows machine. Due to `set /a` they won't work on a DOSBox, or on a DOS machine if you somehow still have one.

### Hello, World!

We can start by writing `hello.bat`:

```
echo Hello, World!
```

Unfortunately it does a very annoying thing, and echos every command before executing it. That's fine for debugging, but not really what we want most of the time:

```
C:\> hello

C:\> echo Hello, World!
Hello, World!

C:\>
```

We can modify this by putting `@` before the command, or we can just disable command echo-ing completely with `@echo off`.

```
@echo off
echo Hello, World!
```

```
C:\> hello2
Hello, World!

C:\>
```

I'm still not sure where that extra newline is coming from, but let's not worry about it for now.

### Variables

We can set variables with `set name=value`, and insert them into other commands with `%name%`.

```
@echo off
set name=Alice
echo Hello, %name%!
```

```
C:\> vars
Hello, Alice!

C:\>
```

This is about the point where we could still run those examples on DOSBox or a DOS machine. From this point on, it's all Windows extensions.

### Math

DOS `.bat` files had no way to do math, but Windows added `set /a` for it:

```
@echo off
set /a a = 40
set /a b = 380
set /a c = %a% + %b%
echo %c%
```

```
C:\> math
420

C:\>
```

### Loop

```
@echo off
set /a i = 1
:loop

echo %i%

set /a i = 1 + %i%

if %i% neq 11 goto :loop
```

```
C:\> loop
1
2
3
4
5
6
7
8
9
10

C:\>
```

What's going on here:

* we set initial value of `i` to 1
* we have a label `:loop`
* every iteration we echo current value of `i`
* then we increase `i` by `1`
* if `i` is not equal to `11`, we jump to `:loop`

### Fibonacci

Functions are hard, so let's do iterative solution. We just do a bunch of variable assignments and additions in a loop. We don't need any new features here:

```
@echo off
set /a i = 1
set /a a = 1
set /a b = 1
:loop

echo fib(%i%)=%a%

set /a i = 1 + %i%
set /a c = %a% + %b%
set /a a = %b%
set /a b = %c%

if %i% neq 21 goto :loop
```

```
C:\> fib
fib(1)=1
fib(2)=1
fib(3)=2
fib(4)=3
fib(5)=5
fib(6)=8
fib(7)=13
fib(8)=21
fib(9)=34
fib(10)=55
fib(11)=89
fib(12)=144
fib(13)=233
fib(14)=377
fib(15)=610
fib(16)=987
fib(17)=1597
fib(18)=2584
fib(19)=4181
fib(20)=6765

C:\>
```

### FizzBuzz

```
@echo off
set /a i = 1

:loop

set /a fizzbuzz = %i% %% 15
set /a fizz = %i% %% 3
set /a buzz = %i% %% 5

set /a t = %i%
if %fizz% == 0 set t=Fizz
if %buzz% == 0 set t=Buzz
if %fizzbuzz% == 0 set t=FizzBuzz

echo %t%

set /a i = 1 + %i%
if %i% neq 101 goto :loop
```

```
C:\>fizzbuzz
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
...
```

We can do `set` conditionally just like we can do `goto`.

### FizzBuzz, modern version

So far I used just DOS features and `set /a`. But Windows added a lot of features to `.bat` files - carefully gating them behind extra sigils and switches to maintain backwards compatibility.

If we wanted to use all the features, here's what FizzBuzz would be like:

```
@echo off
setlocal enableDelayedExpansion
for /l %%j in (1 1 100) do (
  set /a fizz = %%j %% 3
  set /a buzz = %%j %% 5
  set /a fizzbuzz = %%j %% 15
  if !fizzbuzz! == 0 (
    echo FizzBuzz
  ) else if !buzz! == 0 (
    echo Buzz
  ) else if !fizz! == 0 (
    echo Fizz
  ) else (
    echo %%j
  )
)
```

But at this point we might just as well use PowerShell.

### Should you use Windows Batch Files?

No. If you need to script a Windows machine, PowerShell is already there for you. And if it's something more complex, you might just as well use a real programming language.

### Code

[All code examples for the series will be in this repository](https://github.com/taw/100-languages-speedrun).

[Code for the Windows Batch Files episode is available here](https://github.com/taw/100-languages-speedrun/tree/master/episode-72-windows-batch-files).