What's the difference between &! and &| in zsh?

Learn what's the difference between &! and &| in zsh? with practical examples, diagrams, and best practices. Covers shell, zsh, jobs development techniques with visual explanations.

Understanding Zsh Job Control: &! vs. &|

Hero image for What's the difference between &! and &| in zsh?

Explore the subtle yet significant differences between &! and &| in Zsh for background job management and process control.

Zsh, the Z shell, is a powerful command-line interpreter that offers advanced features beyond traditional shells like Bash. Among its many capabilities, Zsh provides sophisticated job control mechanisms. When running commands in the background, you might encounter the operators &! and &|. While both relate to background execution, they serve distinct purposes, particularly concerning job control and process group management. Understanding these differences is crucial for effective scripting and interactive shell use.

The Basics of Backgrounding with &

Before diving into &! and &|, let's quickly review the standard & operator. Appending & to a command runs it in the background, detaching it from the current shell's foreground process. This allows you to continue using the shell while the background process executes. The shell typically prints a job number and the process ID (PID) for the background job.

sleep 10 &
[1] 12345

Running a simple sleep command in the background.

Understanding &! (Disown and Background)

The &! operator in Zsh is a combination of backgrounding a command and immediately disowning it. When a job is disowned, it is removed from the shell's job table. This means the shell will no longer track it, and it will not receive signals like SIGHUP if the shell exits. This is particularly useful for long-running processes that you want to continue even after you close your terminal session, without explicitly using nohup or disown as a separate command.

flowchart TD
    A[Command] --> B{"Append `&!`"}
    B --> C[Execute in Background]
    C --> D[Remove from Shell Job Table]
    D --> E[Process Continues Independently]
    E --> F[Shell Exits (No SIGHUP)]

Flowchart illustrating the behavior of &!.

sleep 30 &!
jobs
# Output: (no jobs listed, or only other active jobs)

Running sleep 30 with &! and checking the job table.

Understanding &| (Background with Job Control)

The &| operator is less common and has a very specific use case related to job control and process groups. It runs a command in the background, but crucially, it places the command in its own process group. This is primarily relevant when you want to ensure that a background process is not affected by signals sent to the foreground process group (e.g., Ctrl+C which sends SIGINT to the foreground process group). However, it still remains in the shell's job table, unlike &!.

flowchart TD
    A[Command] --> B{"Append `&|`"}
    B --> C[Execute in Background]
    C --> D[Place in New Process Group]
    D --> E[Remain in Shell Job Table]
    E --> F[Foreground Signals Don't Affect]
    F --> G[Shell Exits (SIGHUP Sent)]

Flowchart illustrating the behavior of &|.

sleep 30 &|
jobs
# Output: [1]  running    sleep 30

Running sleep 30 with &| and checking the job table.

Key Differences and Use Cases

The primary distinction lies in job table management and signal handling upon shell exit. &! is for complete detachment, while &| is for process group isolation within the shell's job control. Most users will find &! more generally useful for fire-and-forget background tasks.

Hero image for What's the difference between &! and &| in zsh?

Summary of differences between &! and &|.

In summary, choose &! when you want a command to run in the background completely independently of your shell session, even after you close the terminal. Choose &| when you need to isolate a background process into its own process group for signal handling purposes, but still want it managed by the shell's job control (e.g., fg, bg, jobs). For most common backgrounding needs, & or &! will suffice.