FreeCOM SHIFT: Argument Windows, SHIFT DOWN, and Reliable Batch Loops
Understand FreeCOM's positional-argument window, reversible SHIFT DOWN extension, termination tests, and safe diagnostics for multi-argument DOS batch jobs.
FreeCOM’s SHIFT changes which batch argument is visible through %0 to %9. It does not rename files, change the environment, or move the bytes of an external program’s command line. The useful model is a sliding window over the batch invocation’s stored parameter list. Once that model is explicit, scripts with more than nine arguments become straightforward, and several subtle bugs become easy to diagnose.
This article describes the FreeCOM implementation and command documentation reviewed on October 11, 2026. The SHIFT DOWN extension is specifically FreeCOM behavior. Do not carry it into another DOS-compatible shell or Windows cmd.exe script without checking that interpreter’s documentation and testing it separately.
The original window includes the script name
At the initial shift level, %0 refers to the script name, %1 to the first argument, and %9 to the ninth. Running SHIFT advances the window by one: the old %1 becomes %0, the old %2 becomes %1, and the previously inaccessible tenth argument becomes %9.
The implementation stores a shiftlevel in the active batch context. Argument lookup adds that level to the requested positional index. If the resulting index is zero, it returns the script name; if the index is outside the available argument range, it returns an empty string. This is a concrete implementation of the window model rather than a metaphor for removing arguments from a queue.
That explains why a script must preserve information before it shifts. If a later diagnostic needs the original %0, store it before the first SHIFT. Reading %0 after several iterations means reading the current window’s zero position, not necessarily the batch filename.
Observe the mapping with a disposable script
Create WINDOW.BAT in a scratch directory:
@ECHO OFF
ECHO INITIAL 0=[%0] 1=[%1] 2=[%2] 9=[%9]
SHIFT
ECHO FORWARD 0=[%0] 1=[%1] 2=[%2] 9=[%9]
SHIFT DOWN
ECHO BACK 0=[%0] 1=[%1] 2=[%2] 9=[%9]
Run it with uncomplicated tokens:
WINDOW.BAT A B C D E F G H I J K
The expected positional relationships, not a captured machine transcript, are:
initial: %1=A, %2=B, %9=I
forward: %0=A, %1=B, %2=C, %9=J
back: %1=A, %2=B, %9=I
The exact initial %0 display may include the interpreter’s resolved script path. Test relationships rather than asserting that every installation prints an identical pathname. Use plain alphanumeric arguments first so quoting, metacharacters, and path parsing do not obscure the window behavior being tested.
Process an arbitrary number of simple arguments
A conventional loop processes %1, shifts, and repeats until %1 expands to an empty string. For a deliberately restricted input contract consisting of nonempty simple DOS names, this diagnostic loop is sufficient:
@ECHO OFF
:NEXT
IF "%1"=="" GOTO DONE
ECHO PROCESS [%1]
SHIFT
GOTO NEXT
:DONE
ECHO FINISHED
This prints arguments and makes no filesystem changes. Run it with zero, one, nine, ten, and twelve arguments. The tenth-argument case is important because a script that merely enumerates %1 through %9 can appear correct for every smaller test while silently ignoring the rest.
The emptiness comparison is appropriate only within the stated input contract. Quotes or shell metacharacters inside untrusted arguments can change the expanded command’s syntax. A batch file is not a general-purpose safe parser for arbitrary external strings. If a job must accept spaces, nested quotes, or special characters, verify FreeCOM’s splitting and expansion rules for that exact input and use a suitable external utility when a strict parser is required.
Do not hide a destructive operation inside the first test loop. Print the resolved item and intended action, inspect the output, then introduce the actual operation in a disposable directory. This makes an off-by-one error visible before it acts on files.
SHIFT DOWN restores the window, not the world
FreeCOM documents SHIFT DOWN as its reversible extension. The current handler decrements the shift level only when it is nonzero; it does not underflow below the original window. Thus a SHIFT DOWN at the initial level leaves the positional mapping at its start.
Reversibility applies only to argument visibility. It does not undo a file copy, a changed environment variable, an output redirection, or a child program’s work. If the script processed an item before moving the window backward, it needs a separate rule to avoid processing that item again.
This is particularly important in retry logic. A retry can use the same current argument without shifting at all. A “shift, run, shift down on failure” design adds state changes that make error paths harder to inspect. Prefer one clearly documented point where successful processing advances to the next argument.
Preserve the original identity explicitly
FreeCOM’s SET command can save the initial script name or a leading control argument before iteration. For a scratch script using simple arguments:
@ECHO OFF
SET JOBNAME=%0
SET DEST=%1
SHIFT
ECHO JOB=[%JOBNAME%] DEST=[%DEST%] FIRST_INPUT=[%1]
SET JOBNAME=
SET DEST=
After the shift, the original second argument is visible as %1. The snippet illustrates positional ownership; it is not a complete copy or deployment program. Environment variables are another state store, so choose task-specific names and avoid overwriting preexisting values in a reusable shell session. For an operational script, either restore earlier values or document that the variables are reserved by that job.
The parameter list and environment are distinct. Shifting does not change a previously assigned DEST, and assigning DEST does not change the positional window. When diagnosing a wrong destination, print both the saved value and current %1 rather than assuming they still refer to the same argument.
Keep nested invocation boundaries visible
The handler uses the active batch context, and the source distinguishes batch contexts from contexts used for FOR processing. This matters when reading the implementation: a shared variable name does not mean that shifting a batch should advance a FOR loop’s file enumeration.
For scripts that invoke other batch files, test the actual invocation method supported by the installed shell. A caller’s parameter window and a child’s arguments are different lists. Do not infer inheritance of a shift level from the fact that the child received an expanded %1. Pass the intended arguments explicitly and record the values printed at each entry point.
When an external executable is involved, SHIFT changes future expansion in the batch interpreter. It does not retroactively modify an already running program’s parameters. This distinction is useful for debugging jobs that launch a utility and then inspect output: the utility saw the command constructed at launch time, not whatever %1 means later.
Acceptance tests and failure diagnosis
A reliable argument loop should terminate for zero arguments, visit every supplied simple argument exactly once, and reach arguments beyond the ninth. Its diagnostics should retain the original script identity and any saved leading options. Test SHIFT DOWN both after a forward shift and at the initial window, and test two forward shifts followed by one backward shift to expose accidental reset assumptions.
If the first item is skipped, inspect whether an initial shift was intended to consume a leading option or was added unnecessarily. If the loop repeats an item, inspect backward shifts and retry branches. If it never terminates, inspect whether the shift is reachable on every successful path. If an empty-looking token stops processing early, investigate argument parsing rather than treating the display as proof that the source list ended.
For recovery, return to the harmless printing version of the script and reproduce the exact invocation with simple tokens. Establish the parameter mapping first, then add quoting requirements and operational actions separately. The resulting script is easier to trust because its argument contract and state transitions are observable, not buried in a long chain of commands.
Related:
- FreeCOM Interactive Command-Line Editing: History, Cursor Keys, and Completion
- Inside COMMAND.COM: The Resident and Transient Portions of DOS’s Shell
Sources: