Skip to content
shellmap

Detect the operating system

Identify the OS name, version, and architecture from inside a shell.

How to detect the operating system in each shell

Bashunix
uname -a

`uname -a` prints kernel-name + node + kernel-release + kernel-version + machine + processor + hardware-platform + OS. Quick discriminators: `uname -s` = `Linux`/`Darwin`/`FreeBSD`/`MINGW*`/`CYGWIN*`. For Linux DISTRO (Ubuntu vs RHEL vs Alpine) read `/etc/os-release` — `. /etc/os-release; echo $ID $VERSION_ID` gives `ubuntu 24.04`. `lsb_release -a` works on Debian-family but not Alpine/Arch; `/etc/os-release` is the freedesktop standard everyone has.

Zshunix
sw_vers

macOS-only: `sw_vers` prints `ProductName: macOS / ProductVersion: 14.5 / BuildVersion: 23F79`. zsh on Linux: same `uname -a` as bash. Discriminate: `[[ "$OSTYPE" == darwin* ]]` (zsh builtin), or `case "$(uname -s)" in Darwin) ... ;; Linux) ... ;; esac` (portable).

Fishunix
uname -a

Same external `uname`. Fish builtin: `$OSTYPE` not set (that's bash/zsh). Detect via `if test (uname) = Darwin; ...; else if test (uname) = Linux; ...; end`. For Windows-on-fish (rare — usually WSL or Cygwin): `uname -s` returns `MINGW*`/`CYGWIN*`/`Linux` (WSL is detectable as `Linux` with `Microsoft` substring in `/proc/version`).

PowerShellwindows
$PSVersionTable

`$PSVersionTable` includes `PSVersion`, `OS` (full OS string), `Platform` (`Win32NT`/`Unix`/`MacOSX`). For pwsh 7 cross-OS: `$IsWindows` / `$IsLinux` / `$IsMacOS` are auto-set booleans. For Windows VERSION specifically: `(Get-CimInstance Win32_OperatingSystem).Version` returns `10.0.19045` (Win10 22H2) or `10.0.22631` (Win11 23H2). `[System.Environment]::OSVersion.Version` is the same on every pwsh-running OS.

cmd.exewindows
ver

`ver` prints `Microsoft Windows [Version 10.0.19045.4170]` — Windows-only. For more: `systeminfo | findstr /B /C:"OS Name" /C:"OS Version"` (slow — 5–15s — but gives `OS Name: Microsoft Windows 11 Pro / OS Version: 10.0.22631 N/A Build 22631`). The build number `19045` = Win10 22H2; `22631` = Win11 23H2; `26100` = Win11 24H2.

Equivalents listed for Bash, Zsh, Fish, PowerShell, cmd.exe.

Gotchas & notes

  • **Three layers of "OS"**: KERNEL (Linux, Darwin, NT), DISTRO/PRODUCT (Ubuntu 24.04, macOS 14.5, Windows 11 23H2), and RELEASE-CHANNEL (Ubuntu LTS vs current, macOS Sonoma vs Sequoia, Win10 vs Win11). `uname` is kernel; `/etc/os-release` + `sw_vers` + `ver` are product. Scripts that branch on kernel (`Darwin` vs `Linux`) miss distro-level differences (Alpine `musl` vs glibc, Ubuntu `apt` vs RHEL `dnf`).
  • **WSL detection**: WSL2 reports `uname -s = Linux` and a kernel like `5.15.146.1-microsoft-standard-WSL2`. The `microsoft` / `WSL2` substring in `uname -r` or `/proc/version` is the canonical WSL marker. WSL1 has `Microsoft` (capitalized) in `/proc/version`. Distinguish for filesystem perf (WSL2 has full Linux filesystem; WSL1 translates syscalls — much slower on heavy I/O).
  • **Architecture detection**: `uname -m` = `x86_64` / `aarch64` / `arm64` / `i686`. `uname -m` is what the KERNEL was compiled for; `uname -p` (BSD) or `arch` (macOS) is the HARDWARE CPU — they differ on Apple Silicon under Rosetta (kernel arm64, process x86_64). pwsh: `[System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture` = process arch; `OSArchitecture` = OS arch. Common gotcha: Homebrew on Apple Silicon installs into `/opt/homebrew` (arm64) vs `/usr/local` (x86_64) — same machine, two prefixes depending on the shell's arch.
  • **Cross-shell portable OS check** (one bash/zsh/fish-compatible idiom): `case "$(uname -s)" in Darwin) ... ;; Linux) ... ;; MINGW*|CYGWIN*|MSYS*) ... ;; *) echo "unsupported"; exit 1 ;; esac`. For pwsh 7 cross-OS: `if ($IsWindows) {} elseif ($IsMacOS) {} elseif ($IsLinux) {}`. Avoid `$env:OS` (Windows-only) and `OSTYPE` (bash/zsh only — fish doesn't set it).

Related commands

Related tasks