Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Zenity lets a shell script show simple graphical dialogs—such as confirmations, text fields, and file pickers—without building a full desktop application. Dialogs that collect information print it to standard output; buttons and failures are reported through exit status. That distinction is the key to writing scripts that handle input, Cancel, and errors reliably.

Zenity needs access to a graphical desktop session, so it is designed for interactive desktop automation, not unattended jobs on a headless server. Its options and appearance can also vary by installed release and desktop environment.

What Zenity does—and when to use it

Zenity is a command-line utility that displays predefined GTK dialogs from shell scripts. It can add a simple graphical front end to an existing command-line task: ask before deleting files, collect a directory, show a status message, or present a short list of actions. See the Zenity manual for its documented dialog types and options.

It is a good fit when the work is already handled by shell commands and only a few prompts are needed. It is not a general-purpose GUI toolkit: choose a full GTK, Qt, or libadwaita application for complex layouts, many states, persistent application data, or extensive validation. Use a terminal interface instead when the workflow must run without a desktop.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Install Zenity and verify your version

Install the package provided by your distribution. These examples apply to common distribution families; package availability and versions depend on the release and configured repositories.

# Debian or Ubuntu family
sudo apt update
sudo apt install zenity

# Fedora family
sudo dnf install zenity

# Arch family
sudo pacman -S zenity

Then check that the executable is available and inspect the options supported by your local build:

command -v zenity
zenity --version
zenity --help
zenity --help-all

For package-specific diagnostics, use the command for your distribution:

type -a zenity
dpkg -s zenity 2>/dev/null       # Debian/Ubuntu
rpm -q zenity 2>/dev/null        # Fedora/RHEL
pacman -Qi zenity 2>/dev/null    # Arch

Test a basic dialog from the same account and desktop session that will run the script:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
zenity --info --title="Zenity test" --text="Zenity is working."

Zenity releases and GTK dependencies are not uniform across Linux. Debian stable package metadata lists a 4.x package with GTK 4 dependencies, while Ubuntu publishes manuals for both Zenity 3.32.0 and 4.1.99. These are examples of release differences, not a claim that every system uses either version. See Debian’s stable package metadata, the Ubuntu Focal manual, and the Ubuntu Questing manual. Check local help or man zenity before relying on an advanced option.

Understand standard output and exit status

Zenity uses two result channels. An input dialog writes the submitted value to standard output, which command substitution can capture. A question dialog reports the button choice through its exit status. Capture or test the status immediately; another command can overwrite $?.

Capture a text entry

name=$(zenity --entry 
  --title="Name" 
  --text="Enter your name:")
status=$?

if [ "$status" -ne 0 ]; then
    printf '%sn' "Input cancelled or dialog failed" >&2
    exit 1
fi

printf 'Hello, %sn' "$name"

A successful submission can still contain an empty string. Treat cancellation, an empty value, and malformed input as separate cases; validate the value before using it.

Handle a question

if zenity --question 
    --title="Continue?" 
    --text="Proceed with the operation?"; then
    echo "User selected OK"
else
    echo "User selected Cancel or the dialog failed"
fi

If your script must distinguish cancellation, timeout, and other failures, save the status and handle documented values deliberately:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
zenity --question --text="Delete this file?"
status=$?

case "$status" in
    0) echo "Confirmed" ;;
    1) echo "Cancelled" ;;
    5) echo "Timed out" ;;
    *) printf 'Zenity failed with status %sn' "$status" >&2 ;;
esac

Do not assume every release or dialog has identical status behavior. Consult the manual and test the installed version for the paths your script needs.

Show information, warnings, errors, and confirmations

Message dialogs display text and return when the user dismisses them. Question dialogs are the appropriate choice when an operation must wait for an explicit decision.

Information, warning, and error

zenity --info --title="Completed" 
  --text="The backup finished successfully."

zenity --warning --title="Warning" 
  --text="This operation may overwrite existing files."

zenity --error --title="Error" 
  --text="The backup could not be created."

Confirmation with meaningful button labels

if zenity --question 
    --title="Overwrite file?" 
    --text="A file with this name already exists." 
    --ok-label="Overwrite" 
    --cancel-label="Keep existing"; then
    echo "Proceeding with overwrite"
else
    echo "Keeping existing file"
fi

Button labels improve clarity but do not change the need to check the dialog’s status.

Collect and validate text or password input

Text fields

An entry dialog can provide a default value with --entry-text. Validate input in the script before passing it to another command.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
name=$(zenity --entry 
  --title="User name" 
  --text="Enter a non-empty name:" 
  --entry-text="guest")
status=$?

if [ "$status" -ne 0 ]; then
    echo "Input cancelled" >&2
    exit 1
fi

if [ -z "$name" ]; then
    zenity --error --text="A name is required."
    exit 1
fi

printf 'Entered: %sn' "$name"

Password fields

password=$(zenity --password --title="Authentication required")
status=$?

if [ "$status" -ne 0 ]; then
    echo "Password entry cancelled" >&2
    exit 1
fi

A password dialog is an input mechanism, not a secure credential store. Avoid printing or logging secrets, putting them in command-line arguments, or treating a shell variable as protected storage. For real credentials, use an established secret-management mechanism appropriate to the task.

Select files and directories

Choose an existing file

file=$(zenity --file-selection --title="Choose a file")
status=$?

if [ "$status" -ne 0 ]; then
    echo "No file selected" >&2
    exit 1
fi

if [ ! -f "$file" ]; then
    zenity --error --text="The selected path is not a regular file."
    exit 1
fi

printf 'Selected: %sn' "$file"

Choose a directory or save a file

directory=$(zenity --file-selection 
  --directory 
  --title="Choose a directory")
output=$(zenity --file-selection 
  --save 
  --confirm-overwrite 
  --title="Save report")

Check the exit status for these dialogs too before using the result. Options and behavior can differ by release; verify them with zenity --help-file-selection or the local manual.

Select multiple files

files=$(zenity --file-selection 
  --multiple 
  --separator=$'n' 
  --title="Choose files")
status=$?

if [ "$status" -ne 0 ]; then
    echo "Selection cancelled" >&2
    exit 1
fi

while IFS= read -r file; do
    printf 'Selected: %sn' "$file"
done <<< "$files"

This newline-delimited approach is convenient, but Unix filenames can themselves contain newlines. Do not treat newline-separated output as a fully general representation of arbitrary paths. If your workflow must handle every valid filename, choose a data-transfer method and dialog interface that preserve path boundaries rather than assuming a text separator is unambiguous.

Present a list of actions

A list dialog can display rows and return the selected row. Keep the returned values stable if the script uses them to choose actions; avoid making a changeable display label your only internal identifier.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
choice=$(printf '%sn' 
    "Backup home directory" 
    "Check disk space" 
    "Quit" |
  zenity --list 
    --title="Choose an action" 
    --column="Action")
status=$?

if [ "$status" -ne 0 ]; then
    exit 0
fi

case "$choice" in
    "Backup home directory") echo "Starting backup" ;;
    "Check disk space") df -h ;;
    "Quit") exit 0 ;;
    *) zenity --error --text="Unknown selection."; exit 1 ;;
esac

For multiple columns, provide matching column definitions and row data. For example:

zenity --list 
  --title="Processes" 
  --column="PID" 
  --column="Command" 
  1234 bash 
  5678 firefox

List output and multiple-selection behavior should be tested against your local release. Use a stable identifier column when the script needs to map a displayed choice to an action.

Build simple forms, calendar, and color prompts

Forms with multiple fields

result=$(zenity --forms 
  --title="Contact details" 
  --text="Enter contact information" 
  --add-entry="Name" 
  --add-entry="Email" 
  --separator="|")
status=$?

if [ "$status" -ne 0 ]; then
    echo "Form cancelled" >&2
    exit 1
fi

IFS='|' read -r name email <<< "$result"
printf 'Name: %snEmail: %sn' "$name" "$email"

Choose a separator that cannot occur in field values, or handle the output format more robustly if users may enter that character. Some releases also support password or calendar fields in forms; check local help for available options.

Calendar and color selection

date_value=$(zenity --calendar 
  --title="Choose a date" 
  --date-format="%Y-%m-%d")

color=$(zenity --color-selection 
  --title="Choose a color")

Date formatting and available options vary; verify the local calendar help rather than relying on an assumed default.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Show progress for a long-running task

A progress dialog reads updates from standard input. Send percentage values and, optionally, a message beginning with #:

{
    echo "10"
    echo "# Preparing..."
    sleep 1

    echo "40"
    echo "# Copying files..."
    sleep 1

    echo "80"
    echo "# Finishing..."
    sleep 1

    echo "100"
    echo "# Complete"
} | zenity --progress 
    --title="Backup" 
    --percentage=0 
    --auto-close

For actual work, arrange for the task to report meaningful progress rather than displaying a percentage unrelated to its state. The bar is only a display: it does not automatically stop the underlying command when the user presses Cancel.

Understand pipeline status and cancellation

In Bash, PIPESTATUS records the status of each command in the most recent pipeline. Save it immediately, because another command replaces it.

for i in {1..100}; do
    echo "$i"
    echo "# Processing item $i"
    sleep 0.05
done | zenity --progress 
    --title="Processing" 
    --percentage=0 
    --auto-close 
    --cancel-label="Stop"

statuses=("${PIPESTATUS[@]}")
producer_status=${statuses[0]}
zenity_status=${statuses[1]}

if [ "$zenity_status" -ne 0 ]; then
    echo "Progress dialog was cancelled or failed" >&2
    # Add explicit cleanup or worker termination here if required.
fi

This example uses Bash-specific syntax and illustrates status collection; a production script must explicitly arrange how the worker stops and cleans up on cancellation. Pipeline behavior, including what happens to a producer when the dialog closes, should be tested for the commands and shell used.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Write safer Zenity scripts

  • Quote variable expansions. Use rm -- "$selected_file", not rm $selected_file. Quoting preserves spaces and prevents unintended word splitting or glob expansion.
  • Validate values before acting. Check that required input is present and that selected paths meet the task’s requirements.
  • Avoid eval. Never turn user input into shell code. Pass it as a quoted argument instead: grep -- "$pattern" "$file", not eval "grep $pattern $file".
  • Handle expected nonzero statuses explicitly. Cancellation is a normal path. With set -e, commands that return nonzero can terminate a script unexpectedly if the control flow is not designed for them. An if condition often makes the intended handling clearer.
  • Separate GUI availability from task logic. If the dialog cannot open, report an actionable error or provide a deliberate non-GUI route where appropriate.

A common Bash starting point is set -o nounset and set -o pipefail; add set -o errexit only with care around expected failures such as Cancel and pipeline handling.

Handle display-session limitations

Zenity needs an accessible graphical session. It commonly fails when launched from cron, a system service, a container, an SSH session without graphical forwarding, or a root context that cannot access the logged-in user’s display. GTK’s runtime documentation describes environment considerations such as DISPLAY; the exact behavior also depends on session configuration. See GNOME’s GTK runtime documentation.

Inspect the context in which the script runs:

printf 'DISPLAY=%sn' "${DISPLAY-}"
printf 'WAYLAND_DISPLAY=%sn' "${WAYLAND_DISPLAY-}"
printf 'XDG_SESSION_TYPE=%sn' "${XDG_SESSION_TYPE-}"
zenity --info --text="Display test"

Run the test as the same user and from the same launch mechanism as the real script. Do not blindly set DISPLAY=:0 or copy authentication cookies: display addresses and authorization are session-specific. If the job is unattended, use a non-GUI workflow or deliberately integrate it with the user’s desktop session.

Adjust text and presentation carefully

Some Zenity dialogs interpret text as Pango markup. To show literal untrusted content, disable markup where the option is supported:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
zenity --error 
  --no-markup 
  --text="$message"

--no-wrap is available for controlling wrapping in supported dialogs, but sizing and rendering depend on the GTK release, desktop theme, and environment. Check local help for --no-markup, --no-wrap, and related options rather than assuming identical behavior across machines.

Troubleshoot common problems

Symptom Likely cause What to check
zenity: command not found Zenity is not installed or is not on PATH. Install the distribution package and run command -v zenity.
No dialog appears The process cannot access a graphical session. Inspect DISPLAY, WAYLAND_DISPLAY, and the user or service context.
The script waits indefinitely A dialog is waiting for input, or a pipeline stage is blocked. Run the dialog directly and inspect the pipeline stages.
The captured value is empty The user submitted an empty value, or the command failed. Check exit status separately, then validate the value.
Cancel is treated as success The script checks stdout but not the dialog status. Test the status immediately after the dialog.
A list action targets the wrong item The script relies on changeable display labels as identifiers. Return or map a stable identifier.
Multiple selected paths parse incorrectly A filename contains the chosen separator, including a newline. Do not assume delimited text can represent every valid pathname.
The progress window closes but work continues The dialog and worker process are not automatically coupled. Implement explicit cancellation and process cleanup.
Text displays unexpectedly The dialog interprets text as markup. Use --no-markup where supported for literal text.
It works in a terminal but not in cron Cron generally lacks the user’s graphical session. Use a non-GUI workflow or a desktop-session trigger.
Options or appearance changed after an upgrade The installed Zenity or GTK generation differs. Check zenity --version and local help.

Choose an alternative when Zenity is not the right fit

Tool Interface Best fit
Zenity GTK graphical dialogs Small desktop shell scripts with a few prompts.
YAD GTK graphical dialogs Workflows that need controls or customization beyond Zenity; availability and behavior vary.
KDialog KDE/Qt dialogs Scripts where KDE Plasma integration is preferred.
dialog or whiptail Terminal interface SSH, TTY, server, or other headless workflows.
GTK, Qt, or libadwaita application Full graphical application Complex interfaces, persistent state, and a maintainable application rather than a script wrapper.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.