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_pidFish 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 60Throws 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
- Run a command in the background— Launch a long-running command without blocking the current shell session.
- Restart a process— Stop and re-launch a running process — useful for picking up config changes, recovering from leaks, and orchestrated reloads.
- Run multiple commands in parallel— Execute several commands concurrently and wait for them all — useful for batch downloads, fan-out tasks, and CI test sharding.
- Send a signal to a process— Deliver a specific Unix signal to a process — useful for graceful shutdown, config reload, and triggered behaviour.