Skip to content
Search

Exec

lastmod 2026-06-10created 2026-06-101 edits

exec is a shell built-in command that replaces the current shell process with a new command. When you run a command without exec, the shell spawns a new child process and stays alive itself, waiting for that child. With exec, the shell "transforms" into the new command and keeps the same PID.

Process tree difference

Without exec

 PID 100  bash (start-uvicorn)   ← 부모로 계속 살아있음
 └─ PID 101  uvicorn             ← 자식

With exec

 PID 100  uvicorn               ← bash가 uvicorn으로 "변신". PID 그대로 유지

Practical differences

This matters especially in deployment environments (Render, Docker, etc.).

1. Signal delivery (most important)

When Render or Docker stops a container, it sends SIGTERM to PID 1 (the startup process).

  • Without exec: SIGTERM is delivered to bash. By default bash does not forward this signal to the child uvicorn, so uvicorn gets no chance at a graceful shutdown and is forcibly killed with SIGKILL after a timeout. In-flight requests are cut off and connections are not cleaned up.
  • With exec: uvicorn is the process itself, so it receives SIGTERM directly and shuts down cleanly. It finishes in-flight requests before exiting.

2. Exit code

  • Without exec: bash returns its own exit code after the child finishes. If bash logic sits in between, uvicorn's actual exit code can be masked.
  • With exec: uvicorn's exit code is exposed as is, so Render's health/restart decisions become accurate.

3. Saves one process

No bash process is left behind that does nothing but wait. Minor, but clean.

When to use

Situation

Use exec?

The shell launches a single server/command at the end and has nothing more to do

Use (recommended)

Cleanup after running, handling signals yourself with a trap handler, or managing multiple processes is needed

Don't use

When the shell launches a single server at the end and has nothing more to do, exec is the standard approach. It is recommended especially in deployment environments because of graceful shutdown.

Conversely, if the shell still has to do something after running uvicorn (e.g., cleanup after exit, handling signals yourself with a trap handler, managing multiple processes), you should leave out exec.

Example: start-uvicorn

exec uv run uvicorn geo_mlops.app:create_app --factory --host "$HOST" --port "$PORT"

The script above has no cleanup or trap handler, so exec is appropriate.

Note: The earlier read ... < <(...) (host/port resolution) comes before exec, so it is not affected. That part runs first, and the shell is replaced only at the point where uvicorn finally runs.

See also

author Zer0 sitemap