Skip to content
shellmap

execReplace the current shell with another program across all 5 shells

Equivalents in every shell

Bashunix
exec python script.py

Builtin. REPLACES the current shell process with `python` — no fork. After `exec`, control NEVER returns to the script. Common uses: pinning a wrapper to its target (`exec real_program "$@"`), or redirecting file descriptors for the rest of the script (`exec 2>logfile`).

Zshunix
exec python script.py

Same as bash. Zsh also supports `exec -c` (clear environment) and `exec -l` (login-shell-style argv[0] — first char `-`).

Fishunix
exec python script.py

Fish builtin. Same process-replacement semantics — the fish process is gone after `exec`, replaced in place by the new program with the same PID and file descriptors.

PowerShellwindows
& python script.py

PowerShell has NO `exec` (process replacement). The call operator `&` SPAWNS a child. The closest mental model is `Invoke-Command` for remoting, but no native in-place exec — the pwsh process stays alive throughout.

cmd.exewindows
cmd /c python script.py

Cmd has no process-replacement. `cmd /c` spawns a child that runs the program, then returns to your shell. There is no way to replace the cmd.exe parent in place — the process tree always retains the launching cmd.

Worked examples

Replace the shell with another program

Bash
exec python -u long_run.py
Zsh
exec python -u long_run.py
Fish
exec python -u long_run.py
PowerShell
python -u long_run.py; exit

Redirect all subsequent script output to a logfile

Bash
exec > script.log 2>&1
Zsh
exec > script.log 2>&1
Fish
exec > script.log 2>&1

Open a numbered file descriptor for repeated reads

Bash
exec 3< input.txt; read -u 3 line; read -u 3 line2
Zsh
exec 3< input.txt; read -u 3 line; read -u 3 line2

Gotchas

  • `exec` REPLACES the current process — anything AFTER `exec` in the script NEVER runs. Putting commands after `exec PROGRAM` is almost always a bug. The exception is `exec` used WITHOUT a command (for FD redirection only), which keeps the shell alive.
  • `exec` with NO command but WITH redirections (`exec > log.txt`) is the "from now on, write all output to this file" idiom. It DOES NOT replace the process — it just permanently changes the file descriptors of the current shell for the remainder of the script.
  • Inside a subshell `( exec foo )`, only the SUBSHELL is replaced. The parent shell continues normally. This pattern is sometimes used to scope `exec` redirections without polluting the rest of the script — confusing if you don't know about subshell isolation.
  • PowerShell `& python script.py` SPAWNS python as a child of pwsh. Exit code propagation requires `$LASTEXITCODE`. There is no way to make pwsh "become" python — porting bash scripts that rely on `exec` for memory/PID equivalence is fundamentally impossible.
  • Cmd `start /b /wait` is the closest cmd analogue but still SPAWNS a child. The cmd process never goes away during execution — wrappers that `exec` in bash to avoid an extra cmd.exe in the process tree have no Windows-side equivalent.

WSL & PowerShell Core notes

pwshPowerShell deliberately omits process-replacement to keep the runspace alive (for `$?`, `$LASTEXITCODE`, history, modules, profile state). Linux/macOS pwsh has the SAME limitation as Windows pwsh — there is no `exec` in any PowerShell. Bash scripts using `exec` for tail-call style chaining must be redesigned for pwsh.
WSLInside WSL bash, `exec` works exactly like native Linux. From Windows, `wsl exec python script.py` spawns a WSL process that runs python — the Windows-side `wsl.exe` process does NOT exec into python; only the Linux bash inside WSL does.

Related commands