Skip to content
shellmap

Wait for a process to finish

Block until a given process exits — useful for sequencing, dependency-management scripts, and orchestrated shutdowns.

How to wait for a process to finish in each shell

Bashunix
long-task & wait $!
Zshunix
long-task & wait $!
Fishunix
long-task &; wait $last_pid

Fish exposes the last-backgrounded PID as `$last_pid` (bash uses `$!`). `wait` with no args blocks for ALL backgrounded jobs in the current session.

PowerShellwindows
Wait-Process -Id 12345 -Timeout 60

Throws a `TimeoutException` if 60s elapses without exit (unless `-ErrorAction SilentlyContinue`). Multiple PIDs: `Wait-Process -Id @(123,456) -Any` returns when any one finishes.

cmd.exewindows
start /wait myapp.exe

`/wait` blocks the calling cmd window until `myapp` exits. Without `/wait`, `start` returns immediately. There is no native primitive to wait on a PID you didn't launch — shell out to PowerShell `Wait-Process`.

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

Gotchas & notes

  • bash `wait` accepts three call patterns: `wait` (no args — blocks for EVERY backgrounded job in this shell); `wait $!` (the PID of the most recently backgrounded process); `wait $pid1 $pid2 …` (specific PIDs). Crucially, `wait` PROPAGATES the waited child's exit code as its OWN exit code — `cmd & wait $!; echo $?` is the canonical idiom for "run in background and surface the rc". For "wait for ANY one of N jobs", bash 4.3+ adds `wait -n` (NOT available on macOS's default bash 3.2 — `brew install bash`).
  • pwsh `Wait-Process -Id 12345 -Timeout 60` blocks up to 60 seconds and throws `TimeoutException` on timeout (suppress with `-ErrorAction SilentlyContinue` if "still running" is a valid outcome). Multi-PID: `Wait-Process -Id @(123,456)` (waits for ALL) vs `Wait-Process -Id @(123,456) -Any` (returns when any one finishes — analogous to bash `wait -n`). Underlying .NET API for cleaner boolean: `(Get-Process -Id 12345).WaitForExit(60000)` returns `$true` on exit, `$false` on timeout — better for scripts that branch on completion.
  • cmd `start /wait` blocks the SHELL until the launched process exits — useful for installer wrappers (`start /wait setup.exe /S && echo done`). `start /wait /b` blocks without opening a new console window. To wait on a PID you DIDN'T launch yourself, cmd offers nothing native — either poll with `tasklist /fi "pid eq 12345" | findstr 12345` in a loop, or shell out to pwsh (`powershell -NoProfile -Command "Wait-Process -Id 12345 -Timeout 60"`). The poll approach loses exit-code information.
  • WAITING-FOR-FILE-DESCRIPTOR-CLOSE (process has detached but a child or pipe still holds an open write-end) is a different problem from PID wait: `inotifywait -e close_write file` (Linux inotify-tools, `apt install inotify-tools`) blocks until the last writer closes. macOS analog: `fswatch -e Updated file`. pwsh: `[System.IO.FileSystemWatcher]` subscribed to `Changed`/`Renamed` events. Use this when you can't track the PID — e.g. waiting on a Docker container's log file to be fully written, or a daemonized child whose PID you've lost.

Related commands

Related tasks