Shell execution methods determine process creation, environment inheritance, and resource management. Each method serves specific operational requirements.
Core Concepts
A shell translates commands into system calls. The execution method determines:
- Process creation behavior
- Environment variable scope
- File descriptor inheritance
- Signal handling
- Exit status propagation
Execution Methods
| Method | Process | Environment | Exit Status | Use |
|---|
Standard
./script.sh | Creates child process. Parent waits. | Child receives environment copy. Parent unchanged. | Parent $? receives child exit code. | Isolated script execution. |
exec
exec ./app | Replaces current process. | New process inherits environment. | Original process terminates. No exit code. | Process replacement without fork overhead. |
source/.
. ./script.sh | No new process. | Modifies current shell environment. | $? receives last command exit code. | Environment modification, function loading. |
Background
./script.sh & | Creates child process. Parent continues. | Child receives environment copy. | $? is 0 if launch succeeds. Use wait for job status. | Non-blocking execution. |
nohup
nohup ./script.sh & | Creates HUP-immune child process. | Child receives environment copy. | Same as background. | Terminal-independent execution. |
Subshell
(cd /tmp && ls) | Creates child shell. | Child receives environment copy. | Parent $? receives subshell exit code. | Command grouping with isolation. |
daemon
daemon --pidfile=/run/app.pid -- ./app | Creates detached process, reparented to init. | Clean environment. | $? reflects daemon utility status. | System service execution. |
Sequential
cmd1; cmd2 | Same process unless commands fork. | Shared environment. | $? receives last command status. | Unconditional command sequence. |
User Substitution
| Command | Process | Environment |
|---|
su [user] | Creates child shell. | Inherits most variables. HOME and SHELL change. |
su - [user] | Creates login shell. | Sources target user profiles. Original environment discarded. |
su -c "cmd" [user] | Creates non-interactive shell. | Mixed environment. No login profile sourcing. |
Command Substitution
| Method | Syntax | Process | Characteristics |
|---|
| Backticks | `command` | Creates subshell. | Legacy syntax. No nesting without escaping. |
| Dollar Parentheses | $(command) | Creates subshell. | Nestable. POSIX standard. |
| Process Substitution | <(command) | Creates background process with FIFO. | Bash/Zsh specific. Returns file descriptor. |
File Descriptors
| Method | stdin/stdout/stderr | Custom FDs |
|---|
| Standard/Background | Inherited from parent. | Inherited if not closed. |
| exec | Inherited unless redirected. | Inherited. |
| source/. | Shared with current shell. | Shared. |
| nohup | stdin from /dev/null. stdout/stderr to nohup.out. | Closed. |
| daemon | Redirected to /dev/null by default. | Closed. |
Signal Handling
| Method | SIGHUP | SIGINT | SIGTERM |
|---|
| Standard | Propagated from terminal. | Propagated if foreground. | Not propagated. |
| Background | Ignored if job control active. | Ignored. | Not propagated. |
| nohup | Ignored. | Ignored. | Not propagated. |
| daemon | Ignored. | Ignored. | Handled by daemon. |
| source/. | Handled by current shell. | Handled by current shell. | Handled by current shell. |
Process Groups
- Foreground: Commands share terminal process group. Receive keyboard signals.
- Background: Commands run in separate process group. No keyboard signals.
- Pipeline: Commands in pipeline share process group.
- Job Control: Shell manages multiple process groups.
jobs, fg, bg commands control groups.
Exit Status Propagation
| Construct | Exit Status |
|---|
cmd1 && cmd2 | First non-zero or last command. |
cmd1 || cmd2 | First zero or last command. |
cmd1 | cmd2 | Last command in pipeline. |
! command | Inverted command status. |
if command; then... | Command status determines branch. |
Notes
- Fork creates process copy with separate memory space.
- exec avoids fork overhead when parent preservation unnecessary.
- Source modifies current shell state without process boundary.
- Signal disposition (default/ignore/handle) inherited across fork, reset across exec.