Skip to content
shellmap

gpgOpenPGP encryption, signing, and key management — GnuPG across all 5 shells

Equivalents in every shell

Bashunix
gpg --encrypt --recipient RECIPIENT-KEY-ID file

GnuPG (the OpenPGP implementation). On most distros installs as `gnupg` or `gnupg2`; binary is `gpg`. Operates on the keyring under `~/.gnupg/`. `gpg-agent` caches passphrases and brokers smartcard / YubiKey access via `pinentry`. Cleartext output of `--decrypt` goes to stdout — pipe to a file or use `-o`. The `--recipient` value can be any user-ID substring, a key-ID (`0xDEADBEEF`), or a full fingerprint — pick a unique fingerprint to avoid ambiguity in production scripts.

Zshunix
gpg --encrypt --recipient RECIPIENT-KEY-ID file

Same external binary. macOS ships nothing — install via `brew install gnupg` (CLI only) or GPG Suite (GUI + Apple Mail integration). Homebrew installs include `pinentry-mac` for a native passphrase prompt window.

Fishunix
gpg --encrypt --recipient RECIPIENT-KEY-ID file

Same external. Fish ships completion for common subcommands. To bridge `gpg-agent` as the SSH agent in fish: `set -gx SSH_AUTH_SOCK (gpgconf --list-dirs agent-ssh-socket)` and enable `enable-ssh-support` in `~/.gnupg/gpg-agent.conf`.

PowerShellwindows
gpg.exe --encrypt --recipient RECIPIENT-KEY-ID file

PowerShell has NO built-in OpenPGP. Install Gpg4win (`choco install gpg4win` / `winget install GnuPG.Gpg4win`) for `gpg.exe`. The built-in `Protect-CmsMessage` / `Unprotect-CmsMessage` cmdlets use X.509 / S/MIME — a DIFFERENT standard, INCOMPATIBLE with OpenPGP messages.

cmd.exewindows
gpg.exe --encrypt --recipient RECIPIENT-KEY-ID file

Same Gpg4win binary. No native OpenPGP. cmd cannot decrypt anything OpenPGP-encrypted by a Unix peer without Gpg4win installed. Sysinternals does not include a gpg client.

Worked examples

Encrypt a file for one recipient with ASCII-armored output

Bash
gpg --encrypt --armor --recipient 0xDEADBEEF secret.txt
Zsh
gpg --encrypt --armor --recipient 0xDEADBEEF secret.txt
PowerShell
gpg.exe --encrypt --armor --recipient 0xDEADBEEF secret.txt

Decrypt a file (agent prompts for the private-key passphrase)

Bash
gpg --decrypt secret.txt.asc > secret.txt
PowerShell
gpg.exe --decrypt secret.txt.asc | Set-Content secret.txt -Encoding UTF8

Sign a release tarball with a detached signature

Bash
gpg --detach-sign --armor release-1.2.3.tar.gz
PowerShell
gpg.exe --detach-sign --armor release-1.2.3.tar.gz

Gotchas

  • OpenPGP (`gpg`) and S/MIME (PowerShell `Protect-CmsMessage`, `openssl smime`) are different standards with incompatible message formats. A file encrypted with `gpg --encrypt` cannot be decrypted by `Unprotect-CmsMessage` — those use X.509 certificates while GPG uses OpenPGP keys.
  • Smartcards / YubiKeys go through `pinentry`. Scripts run by cron / systemd / a CI runner often have no TTY to prompt on — set `pinentry-mode loopback` and pass the PIN via `--passphrase-fd 0`, or use a passphrase-less subkey for unattended signing. Confirm card state with `gpg --card-status`.
  • Windows has NO built-in OpenPGP — Gpg4win is the de-facto stack. Cross-platform CI that signs both Unix and Windows artefacts should install Gpg4win on the Windows runner, not roll its own encryption layer. The PowerShell `Get-CmsMessage` / `Protect-CmsMessage` family are S/MIME-only and cannot read OpenPGP.
  • Inside WSL the Linux `gpg-agent` is INDEPENDENT from a Windows-side Gpg4win agent — same key file on `/mnt/c` does NOT mean a shared agent session. To forward the Linux `gpg-agent` socket (`~/.gnupg/S.gpg-agent.extra`) into Windows-side SSH use, bridge with `weasel-pageant` or import the key into both keyrings.
  • `gpg --gen-key` defaults differ by version. Modern GnuPG 2.2+ generates RSA-3072 with a 2-year expiry; older 2.0 generated RSA-2048 with no expiry. For reproducible provisioning use `gpg --quick-generate-key 'Name <email>' ed25519 cert,sign 2y` so the key shape is fixed regardless of the host's default.

WSL & PowerShell Core notes

pwshPowerShell Core has no native OpenPGP cmdlets on any platform — the standard approach is to call the system `gpg` binary (`gpg` on Linux/macOS, `gpg.exe` from Gpg4win on Windows) via `& gpg ...` or `Start-Process`. Capture the result code with `$LASTEXITCODE`; non-zero means the operation failed (often a bad passphrase or missing public key).
WSLTwo completely separate keyrings live side by side: the WSL Linux distro under `~/.gnupg/` and Windows Gpg4win under `%APPDATA%\gnupg\`. Importing a private key into one does NOT make it available to the other. To use a YubiKey from both worlds you need `usbipd-win` to forward the device — but only one side can claim it at a time.

Related commands