Skip to content
shellmap

List installed packages

Print every package installed by the OS-level package manager — for inventory, security audits, reproducing a system on another machine, or "what got pulled in as a dep that I never asked for".

How to list installed packages in each shell

Bashunix
apt list --installed

Debian/Ubuntu. Equivalent older form: `dpkg -l` (more verbose, machine-parseable columns). Variants: `dnf list installed` (Fedora/RHEL), `pacman -Q` (Arch — short: package + version), `pacman -Qe` (explicitly-installed only — skips deps), `brew list --versions` (macOS), `apk info` (Alpine), `zypper se --installed-only` (openSUSE).

Zshunix
apt list --installed
Fishunix
apt list --installed
PowerShellwindows
winget list

Lists EVERYTHING winget knows about — both winget-installed and Programs-and-Features-installed (winget reads the Windows installed-apps registry too). To filter: `winget list --source winget` (only ones managed by winget). For PowerShellGet modules separately: `Get-InstalledModule`. For .NET tools: `dotnet tool list -g`. For all three in one pass: `winget list; Get-InstalledModule; dotnet tool list -g`. To diff against a baseline: `winget list | Out-File baseline.txt`, then later `winget list | Compare-Object -ReferenceObject (Get-Content baseline.txt)`.

cmd.exewindows
winget list

Same `winget.exe`. Chocolatey alternative: `choco list --local-only` (older form `choco list -lo`). Scoop: `scoop list`. The legacy `wmic product get name,version` works but is DEPRECATED (Windows 11 24H2 removed WMIC by default; install via `OptionalFeature WMIC`). For full Programs-and-Features dump: `reg query "HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall" /s /v DisplayName` — registry-direct, no tool dependency.

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

Gotchas & notes

  • **`apt list --installed` vs `dpkg -l` — same data, different ergonomics.** `apt list --installed` (Debian 9+, Ubuntu 16.04+) prints `package/suite,now version arch [installed,...]` — easy to read, the modern form. `dpkg -l` prints a fixed-column table with status flags (`ii` = installed-ok-installed, `rc` = removed-but-config-present, etc.) — machine-parseable. For "give me a one-package-per-line list": `dpkg --get-selections | awk '/install$/{print $1}'`. For "show me explicitly installed (not pulled in as deps)": `apt-mark showmanual`. The distinction matters when reproducing a system — you want to reinstall what you ASKED for, not the 800 transitive deps. Equivalent on Arch: `pacman -Qe` (explicit) vs `pacman -Q` (everything); on Fedora: `dnf repoquery --userinstalled`.
  • **"List packages from this repo" (security audit angle).** Debian: `apt list --installed 2>/dev/null | grep -v "/now,now" | awk -F/ '{print $2}' | sort -u` lists which suites your installs came from (security-updates vs universe vs third-party PPAs). Fedora: `dnf repoquery --installed --queryformat "%{name} %{repoid}"` shows the source repo for each installed package — security review use case is "which packages came from RPM Fusion (third-party) vs official?". Useful for "are any installed binaries unsigned / from an EOL PPA?". On macOS: `brew list --formula` + `brew --repository` to identify which tap each formula came from. Audit the third-party taps to know who you trusted.
  • **Snap / Flatpak / AppImage are SEPARATE inventories on Linux.** `apt list --installed` does NOT show snap packages — those are tracked by `snap list` (Ubuntu default for many GUI apps since 22.04). Flatpak: `flatpak list` (`--app` for apps only, `--runtime` for runtimes). AppImage: no central registry — they're standalone binaries scattered across `~/.local/bin`, `~/Applications`, etc. (find with `find ~ -name "*.AppImage" 2>/dev/null`). nix: `nix-env --query --installed` for the user profile, `/run/current-system/sw/bin` for the system profile (NixOS only). For a complete inventory, query EVERY package manager you've used — single source of truth doesn't exist on most Linux desktops.
  • **Output format and machine consumption.** apt/dnf default output is human-readable, not stable. For scripting use the format flags: `apt list --installed 2>/dev/null` is fine for quick eyeball but unreliable in CI. Robust forms: Debian `dpkg-query -W -f '${Package} ${Version}\n'` (printf-style format); Fedora `rpm -qa --queryformat "%{NAME} %{VERSION}\n"`; Arch `pacman -Q` (already simple `name version`); Brew `brew list --versions` (`pkg version1 version2 ...` — multiple-version installs space-separated on one line, a parsing gotcha); winget `winget list --output json` (winget 1.6+) — JSON for pwsh `ConvertFrom-Json` pipelines. Always check the package manager's "stable parseable" mode before piping to `awk`.
  • **System-image reproduction recipe.** "I want to recreate this machine's installs elsewhere": Debian — `dpkg --get-selections > selections.txt` then on the new box `sudo dpkg --set-selections < selections.txt && sudo apt-get dselect-upgrade`. Fedora: `dnf repoquery --userinstalled --queryformat "%{name}\n" > installed.txt` then `xargs sudo dnf install < installed.txt`. Arch: `pacman -Qqe > installed.txt` then `pacman -S --needed - < installed.txt`. macOS Homebrew: `brew bundle dump --file=Brewfile` then `brew bundle --file=Brewfile` (formulae + casks + taps + mas-cli App Store apps). Windows winget: `winget export -o packages.json` then `winget import -i packages.json`. The export-then-import idiom beats "list and parse" — package managers know their own state best.

Related tasks