COMMAND.COM
A COMMAND.COM for Unix - because some of us never got over losing
that C:\> prompt, and now we can impose it on perfectly innocent
Linux systems.
Module: codeberg.org/lyda/command-com
Binary: COMMAND.COM
The shell provides a DOS 3.3 style command interface over a normal
Unix host. It is not a DOS emulator - there is no FAT filesystem, no
.EXE/.COM execution, no BIOS. What you get is a familiar-feeling
interactive shell with DOS-style path notation, .BAT file execution,
and even EDLIN and TURGO (a Turbo Pascal-style IDE for Go) for that
real 1986 development experience.
Installation
Pre-built binaries for Linux, FreeBSD, NetBSD, OpenBSD, DragonFly BSD,
Solaris, illumos, AIX, and macOS are available on the
releases page.
Linux builds cover amd64, arm64, 386, arm, and riscv64. Other platforms
cover amd64 and/or arm64 where supported by Go.
Or install from source with Go:
go install codeberg.org/lyda/command-com/cmd/command.com@latest
The binary is called COMMAND.COM. To use it as a login shell:
# copy to a location in /etc/shells
sudo cp $(go env GOPATH)/bin/COMMAND.COM /bin/COMMAND.COM
echo /bin/COMMAND.COM | sudo tee -a /etc/shells
chsh -s /bin/COMMAND.COM
Quick start
A:\>ver
Go COMMAND.COM version 0.1
A:\>prompt $p$g
A:\>cd \projects
A:\projects>dir
A:\projects>type build.bat
@echo off
echo Hello from COMMAND.COM
A:\projects>edlin notes.txt
New file
*I
1: Hello, world
.
*E
notes.txt written
Drive mapping
The shell maps DOS drive letters to Unix directory trees.
| Drive |
Default mapping |
C: |
/ (filesystem root) |
A: |
~ (your home directory) |
Additional mappings may be configured in ~/config.sys (see
Configuration). Switch drives with a bare A: or C:.
Paths may use \ or / as separators. Output always uses \.
Interactive features
- Line editing - cursor movement, history recall (up/down arrows), home/end
- Command history - persisted to
~/.command_history across sessions
- Tab completion - built-in command names, executables in
PATH, DOS-style paths
- Ctrl-C - cancels the current input line; does not exit the shell
- Configurable prompt - see Prompt sequences
- Startup scripts -
/etc/autoexec.bat and ~/autoexec.bat run at login
Invocation modes
COMMAND.COM # interactive shell
COMMAND.COM /C "DIR A:\tmp" # run one command and exit
COMMAND.COM /K "CD A:\work" # run one command, then stay interactive
COMMAND.COM script.bat [args] # run a batch file and exit
Built-in commands
Navigation
| Command |
Effect |
A:, C:, ... |
Switch to drive |
CD [path] / CHDIR [path] |
Print or change current directory |
MD path / MKDIR path |
Create directory |
RD path / RMDIR path [/S] |
Remove directory (/S = recursive) |
Files
| Command |
Effect |
DIR [path] |
List directory |
TYPE file |
Print file contents |
COPY src dest |
Copy file (NUL accepted as destination) |
DEL file / ERASE file |
Delete file (glob patterns accepted) |
REN old new / RENAME old new |
Rename file |
ATTRIB [file] |
Show synthetic file attributes (R=read-only, H=hidden) |
Environment
| Command |
Effect |
SET [name[=value]] |
List, get, or set environment variables |
PATH [value] |
Print or set PATH |
PROMPT [template] |
Set prompt; no argument resets to default |
Shell
| Command |
Effect |
VER |
Print version |
CLS |
Clear screen |
ECHO [text] / ECHO ON / ECHO OFF |
Print text or control command echoing |
PAUSE |
Wait for any key |
REM text |
Comment (no-op) |
DATE |
Print current date |
TIME |
Print current time |
EXIT [n] |
Exit shell with optional exit code |
Batch / control flow
| Command |
Effect |
GOTO label |
Jump to :label in current batch file |
CALL file [args] |
Run nested batch file and return |
SHIFT |
Shift positional parameters (%2->%1, %3->%2, ... - first arg discarded) |
IF ... |
Conditional - see IF forms |
Editor
| Command |
Effect |
EDLIN file |
Open file in the line-oriented EDLIN editor |
IF ERRORLEVEL n command
IF NOT ERRORLEVEL n command
IF EXIST file command
IF NOT EXIST file command
IF string==string command
IF NOT string==string command
IF ERRORLEVEL n is true when the current ERRORLEVEL is >= n (DOS semantics).
Redirection and pipes
command > file redirect stdout
command >> file append stdout
command < file redirect stdin
command 2> file redirect stderr
command 2>> file append stderr
command 2>&1 merge stderr into stdout
command | command pipe
command && command run second only if first succeeds
command || command run second only if first fails
The 2>, 2>>, 2>&1, &&, and || operators are extensions beyond classic
DOS; they are available in the default (practical) mode.
Prompt sequences
| Sequence |
Output |
$P |
Current path (e.g. A:\work) |
$G |
> |
$M |
Machine name (extension) |
$N |
Current drive letter |
$Q |
= |
$S |
Space |
$T |
Current time |
$U |
User name (extension) |
$D |
Current date |
$$ |
Literal $ |
Default prompt: $P$G -> A:\work>
Batch scripting
.BAT files are plain text scripts, executed line by line.
@ECHO OFF
REM This is a comment
SET GREETING=Hello
IF NOT EXIST output.txt GOTO build
ECHO Already built.
GOTO end
:build
ECHO %GREETING%, world > output.txt
ECHO Built.
:end
What works
- Line-by-line execution
@ echo-suppression prefix
ECHO ON / ECHO OFF
- Labels (
:label) and GOTO
CALL file [args] for nested batch files, CALL :label for local subroutines
SHIFT for positional parameter handling
FOR %V IN (list) DO cmd - literal list iteration
FOR /L %V IN (start,step,end) DO cmd - numeric range iteration
%0..%9 positional parameters
%VARNAME% variable expansion
%% for a literal % in batch context
IF in all four forms with optional NOT
ERRORLEVEL set by built-ins and external commands
- All redirection and pipe operators
REM and :: comments
- Any form of arithmetic except shift operators (
SET /A)
- String manipulation (
%VAR:old=new%, substrings)
SETLOCAL / ENDLOCAL variable scope - SETLOCAL ENABLEDELAYEDEXPANSION enables !VAR!
What does not work
- Parenthesized multi-line blocks (
IF (...) ELSE (...))
EDLIN
EDLIN is a line-oriented text editor. All commands are case-insensitive.
Addresses: an integer, . (current line), or $ (last line).
A:\>edlin notes.txt
Editing 3 lines
*1,3L list lines 1 through 3
*2I insert before line 2 (end input with a line containing only .)
*A append after current line
*3D delete line 3
*1,3D delete lines 1 through 3
*Sfoo search for "foo"
*1,$Sfoo search entire file for "foo"
*R replace (prompts for search/replace strings)
*U undo last change
*W write file without exiting
*E write file and exit
*Q quit without saving (confirms if there are unsaved changes)
*H help
Pressing Enter on a blank line advances to the next line and displays it.
Turbo Go 3.0
TURGO opens an interactive IDE inspired by Turbo Pascal 3.0. It runs
entirely in the terminal using ANSI escape sequences - no TUI library.
A:\projects>turgo main.go
Turbo Go system Version 0.1
Logged drive: A
Work file: main.go
Edit Build Run Save
Dir Quit Options
Text: 1234 bytes
Last result: Build OK
>
| Key |
Action |
E |
Open work file in $EDITOR (default: vi); jumps to error line for joe/jed/vim/nano |
B |
go build ./...; error shown in Last result |
R |
go run <workfile>; output fills screen; any key to return |
S |
Set work file name |
D |
Directory listing of current drive |
O |
Options sub-menu (work file, build flags) |
Q |
Return to COMMAND.COM prompt |
Set EDITOR=edlin to use the built-in editor (invoked via COMMAND.COM /C EDLIN).
Set EDITOR=joe (or jed, nano, vim, nvim, etc.) to jump directly to the error line.
For the most authentic Turbo Pascal experience, use joe or jed.
Configuration
~/config.sys (INI format with sections):
[drives]
D = /mnt/data
E = /media/usb
[shell]
; Prompt default (used when PROMPT env var is unset)
prompt = $P$G
; Set to false to skip /etc/autoexec.bat and ~/autoexec.bat at login
startup = true
[history]
file = ~/.command_history
Deliberately not supported
The following are intentional non-goals, not gaps:
- Execution of DOS
.COM or .EXE binaries
- FAT or NTFS filesystem semantics
- 8.3 filename enforcement
- Full compatibility with arbitrary real-world DOS batch files
- DOS device names (
CON, PRN, AUX) - NUL maps to /dev/null
- Hardware commands:
FORMAT, FDISK, DISKCOPY, SYS, DEBUG, MODE, MEM,
CTTY, LABEL (these are registered as stubs that print an error)
- Case-sensitive path comparison (paths are matched case-insensitively by default)
Architecture
cmd/command.com/ main entry point, flag dispatch, interactive loop
internal/
builtins/ built-in command implementations and registry
exec/ command dispatcher, pipeline, redirection, IF handling
batch/ batch execution engine: labels, GOTO, CALL, ERRORLEVEL
parser/ tokenizer and command-line parser
fsmap/ DOS path <-> Unix path mapping, per-drive CWD
env/ case-insensitive environment and variable expansion
prompt/ prompt string rendering
edlin/ EDLIN line editor
term/ readline wrapper (history, completion, Ctrl-C handling)
config/ ~/config.sys loader
All packages are internal; the only public API surface is the command.com binary.
External runtime dependency: github.com/peterh/liner for line editing.
License
See the LICENSE file.