Skip to content
FreeDOSHow-To Published Updated 4 min readViews unavailable

How to Use FreeCOM Batch Features Beyond a Linear Startup Script

Build reusable FreeCOM batch routines with arguments, labels, error handling, controlled environments, safe temporary files, and predictable quoting.

Most FreeDOS batch files people actually write are linear scripts — a fixed sequence of commands run top to bottom. FreeCOM, FreeDOS’s command interpreter, supports considerably more structure than that, and using it turns a fragile startup script into something closer to a genuinely reusable routine.

Step 1: document the input contract before writing any logic

Start every script with a comment block stating exactly what arguments it expects, in what order, and what each one means. A batch file with no stated contract becomes something only its original author can safely modify — an explicit, documented contract is what makes a routine safe for someone else (including a future version of yourself) to call without re-reading the entire script first.

Step 2: validate before anything destructive runs

IF NOT EXIST %1 GOTO :usage
IF "%2"=="" GOTO :usage

Check that required files exist and required arguments were actually supplied before any command that deletes, overwrites, or formats anything. A missing-argument case that isn’t caught explicitly tends to be silently interpreted as an empty string by later commands, which can turn a typo into unintended data loss rather than a clean, early error message.

Step 3: structure reusable routines with labels and CALL

CALL :dolog "starting backup"
GOTO :main
:dolog
ECHO %1 >> LOGFILE.TXT
GOTO :EOF
:main

Calling a second batch file (or a label within the same file) directly, without CALL, transfers control to it permanently — the original script never resumes. CALL is specifically what lets a labeled routine run “inside” the calling script and return control afterward, which is the actual mechanism that makes reusable subroutines possible within a single FreeCOM batch file.

Step 4: return meaningful ERRORLEVEL values

FreeCOM tracks the exit code of the most recently run program in its ERRORLEVEL mechanism, checked with IF ERRORLEVEL n. A script that always exits silently regardless of what happened inside it gives its caller nothing to branch on — deliberately setting and checking ERRORLEVEL at each meaningful step is what lets a calling script distinguish “completed successfully” from “failed partway through” instead of just assuming success.

Step 5: keep environment changes bounded

Confirm whether your specific installed FreeCOM version supports SETLOCAL/ENDLOCAL-style environment scoping before relying on it — support and exact behavior have varied across FreeCOM versions and forks, unlike the equivalent, more consistently available feature in Windows’s cmd.exe. Where scoping isn’t reliably available, explicitly save and restore any environment variables your script modifies, rather than assuming they’ll be cleaned up automatically when the script ends.

Step 6: quote carefully, and don’t assume uniform parsing

Quote paths containing spaces wherever the specific command you’re calling actually supports quoted arguments — DOS-era utilities differ noticeably in how (or whether) they parse quotes, unlike the more standardized argument handling modern shells provide. Redirect diagnostic detail to a log file, and echo only a concise, human-readable failure summary to the screen, so a user running the script interactively isn’t overwhelmed with debug output during normal operation.

Step 7: test under the real target FreeCOM, not just cmd.exe

Test with empty arguments, a full disk, and a deliberately interrupted command, and do this testing under the actual FreeCOM version shipped with your target system rather than assuming a script that works in Windows’s cmd.exe behaves identically — the two interpreters share batch-file ancestry but have diverged enough that cmd.exe-specific syntax is a common, avoidable source of scripts that fail only once deployed to real FreeDOS.

Why piping behaves differently than you might expect

Like the original COMMAND.COM it’s a free reimplementation of, FreeCOM implements pipes (|) using temporary files under the hood rather than true concurrent inter-process pipes — DOS itself has no real multitasking pipe mechanism, so a piped command actually runs the first program, captures its output to a temporary file, then runs the second program reading from that file. This has real practical consequences: a piped command chain that would run concurrently on a genuinely multitasking OS runs sequentially under FreeCOM, and a script that fills the disk with output right before a pipe can fail in a way a modern shell’s true streaming pipe wouldn’t.

Keeping the whole routine debuggable as it grows

As a batch file accumulates labeled routines called via CALL, add an explicit ECHO trace at the entry point of each routine while developing it, then strip or gate those traces once the routine is confirmed working — a multi-routine batch file with no visibility into which labeled section is currently executing becomes considerably harder to debug than the same logic written as one long linear script, which is the exact complexity trade-off worth being deliberate about as a script grows. Related: Writing Batch Files on FreeDOS · Running FreeDOS Today: Virtualization, Real Hardware, and Use Cases

Sources: