Mastering DOS to Unix Command Line Transitions: Techniques for Real-World Cross-Platform Operations
Misinterpreted command lines can trigger silent failures and data loss, especially during migration or hybrid operations. Anyone involved in maintaining mixed Windows (cmd.exe, PowerShell) and Unix-like (Linux, BSD, macOS) systems will eventually run into these hazards. A partial script port, a careless path typo, or the wrong command flag—impact can range from mere annoyance to halted CI/CD pipelines.
Problem Statement: One Script, Two Worlds
Consider a migration project: Windows batch scripts automate data archival, but new workloads are moving to a Linux-based environment. The original batch file assumes %USERNAME%
and path delimiters as \
. Unix sees those and can’t resolve paths or variables, aborts with errors, or worse—silently truncates data. Simple as it sounds, even the classic:
COPY C:\data\*.* D:\backup\
fails when naively converted as:
cp C:\data\*.* D:\backup\
Yield: cp: cannot stat 'C:\data\*.*': No such file or directory
.
DOS vs. Unix Command Line—Operational Differences
The devil is in the details. Table summarizing operational differences:
Feature | DOS/Windows | Unix/Linux |
---|---|---|
Path Separator | \ | / |
Case Sensitivity | Insensitive | Sensitive |
Variables | %VAR% | $VAR |
Switch Prefix | / | - /-- |
Home Directory | %USERPROFILE% | $HOME or ~ |
Wildcards | * ? (some shell limitations) | * ? [] {} (globbing rules) |
Built-ins | DIR , COPY , MOVE | ls , cp , mv |
Scripting extension | .bat or .cmd | .sh |
Note: PowerShell has its own nuances ($env:VAR
, \
paths, etc.), and WSL/MinGW/Cygwin blur lines further.
Command Equivalents and Syntax Adjustments
Real-world scripts rarely stick to trivial patterns. Still, the following equivalence table helps when retrofitting job steps or CI runners:
Task | Windows Command | Unix Command |
---|---|---|
List directory | DIR | ls -al |
Change directory | CD path | cd path |
Copy file(s) | COPY src dst | cp src dst |
Delete file | DEL file | rm file |
Move/Rename | MOVE old new | mv old new |
Gotcha: Windows COPY
won’t handle directories recursively (use XCOPY src dst /E /I
), while Unix cp -r
is the standard. Path normalization is not automatic between environments.
Example: Converting a Backup Script
Batch:
@echo off
set SRC=C:\data
set DST=D:\backup
xcopy %SRC%\*.* %DST% /E /I
Bash:
#!/bin/bash
SRC="/data"
DST="/backup"
cp -r "$SRC/"* "$DST/"
Trade-off: Recursive copy in Unix is explicit, and globbing matches dotfiles only with shopt -s dotglob
(Bash, 4.0+)—not a perfect translation.
Scripting Differences That Bite
Loops
- Batch:
FOR %%f IN (*.csv) DO TYPE %%f >> all_data.txt
- Bash:
for f in *.csv; do cat "$f" >> all_data.txt; done
Known issue: Batch variables (%%
) vs. shell expansion. Batch error-handling (ERRORLEVEL
) doesn’t map directly to $?
or set -e
in shell scripts.
Environment Variables
Echoing variables breaks if you forget syntax:
- Batch:
%COMPUTERNAME%
- Bash:
$HOSTNAME
Migrating scripts that reference environment variables is a common failure point.
Translating Paths: Details Matter
- Remove drive letters. Map logical drives to mount points (example:
D:\
→/mnt/d
with WSL, or custom mounts in fstab). - Replace backslashes with forward slashes.
- Watch for spaces in filenames—wrap in quotes, or prefer tab-completion.
Practical Example:
Batch:
C:\Users\admin\Documents\My Files\
Bash:
/home/admin/Documents/My\ Files/
Or, for interoperability (spaces):
/home/admin/Documents/"My Files"/
Carriage Return Gotchas: dos2unix Utility
Migrated scripts sometimes throw:
bash: ./deploy.sh: /bin/bash^M: bad interpreter: No such file or directory
Cause: Windows line endings (CRLF) vs. Unix (LF).
Fix:
dos2unix deploy.sh
Alternative: Use sed -i 's/\r$//' deploy.sh
for a one-liner.
Non-Obvious Pitfalls
- Case Sensitivity: Don’t assume
readme.txt
andREADME.txt
are the same. - Permissions: Unix requires
chmod +x script.sh
for executables. - Trailing Slashes:
rm -rf /tmp/dir
versusrd /s /q C:\tmp\dir
. - Wildcards:
del *.log
in Windows vs.rm *.log
—but Bash patterns are more powerful (e.g.,rm *.{log,txt}
).
Tooling Strategies
When true cross-platform scripting is required:
- PowerShell Core (>= 7.x): Nearly identical across Windows/macOS/Linux, but syntax differs from CMD and Bash.
- WSL2 (Windows 10/11): Native Linux compatibility, avoids most path issues but still requires context switching.
- Cygwin/MSYS2: Offers GNU toolchain on Windows, but not always portable to pure Linux.
- git-bash: Suitable for lightweight Unix commands in Windows-centric DevOps workflows.
Side Note: Not all Windows subsystems handle signals (e.g., SIGINT) or device files the Unix way—build guards into your scripts if signals or device paths matter.
Transition Checklist
- Map command equivalents: Create a conversion chart for your environment.
- Normalize paths: Use scripts or text editor macros to convert path delimiters in bulk.
- Convert line endings: Run
dos2unix
after code checkout or transfer. - Verify variables: Lint scripts for variable reference mismatches.
- Test under native shell: Don’t trust Cygwin/WSL/PowerShell emulation for production validation.
- Document known workarounds: Not every construct is portable—keep notes for the next engineer.
Final thought: Cross-platform command line work is rarely perfect. Allow time for iterative adaptation; test edge cases (strange filenames, deep paths, permissions) and document what breaks and why. Gaps will emerge—track them and revisit with each major OS or shell update.