October 12, 2021 by Olivier Goffart and Simon Hausmann

Showing GUIs from Shell Scripts

Ever written a quick (shell) script to automate a small task at some point? Then that script grew over the years and perhaps ended up in the hands of way more users than you originally anticipated? If you were lucky enough to experience this, maybe you wondered: Wouldn't it be nice to have a GUI for that script?

Update: (April 2024) Converted naming from SixtyFPS to Slint and updated to Slint 1.0 syntax.

Now, you probably don't want to rewrite this script in another language to get access to powerful GUI libraries. But you still want to use a proper GUI library. And you also want something that accepts and returns complex, structured data. Finally, this GUI should run everywhere that script runs.


If you have rust/cargo installed, copy this code snippet and paste it into your shell on Linux or macOS.


# install slint-viewer (do nothing if it is already installed)
cargo install slint-viewer

output=$(slint-viewer - --save-data - << EOF
import { StandardButton, LineEdit, GridBox } from "std-widgets.slint";
export component _ inherits Dialog {
    StandardButton { kind: ok; }
    StandardButton { kind: cancel; }
    in-out property name <=> name-le.text;
    in-out property address <=> address-le.text;
    GridBox {
        Row {
            Text { text: "Enter your name:"; }
            name-le := LineEdit { }
        Row {
            Text { text: "Address:"; }
            address-le := LineEdit { }
if [ $? -eq 0 ]; then
    name=`echo $output | grep -o '"name": *"[^"]*"' | grep -o '"[^"]*"$'`
    address=`echo $output | grep -o '"address": *"[^"]*"' | grep -o '"[^"]*"$'`
    echo "Your name is $name and you live in $address"
You should see the following dialog. When you click OK, it prints Your name is "Olivier" and you live in "Berlin".

Screenshot of slint-viewer

Using Slint from Shell Scripts

Slint is a new GUI framework for desktop and embedded applications. It is written in Rust but can be used from other programming languages.

The slint-viewer utility is a tool that we introduced to preview .slint design markup files. Since it is written in Rust, you can install it by running cargo install slint-viewer. Besides the preview functionality, we have added features that help you show GUIs from shell scripts.

The .slint design markup language describes your UI in a declarative way with a familiar syntax. Check out our language reference for details.

With slint-viewer, you can either load a .slint file, or pass a "-" to load from stdin. The design is then shown on the screen and you can interact with it like a real application.

What's new is that any properties declared at the top-level can be loaded and saved with JSON. The --save-data - option causes the the viewer to write the properties as key-value pairs to stdout when quitting, or you could also write it into a temporary file. The --load-data option reads a JSON object and populates the key-value pairs to the properties declared at the top-level.

To persist the value of widgets like LineEdit, declare aliases, similar to the teaser example: property name <=> name-le.text; This re-exports the name-le's text property as "name".

SysInfo Example

You can find a more advanced example in our Git repository: This sysinfo_linux.sh script collects information about your system, formats it to JSON, feeds it into slint-viewer and presents a system information dialog. Next to it is sysinfo_mac.sh script that does the same for macOS, and they both use the same user interface file.

On Linux it looks like this:


These examples demonstrate a simple way of separating a dialog user interface from input and output data. There are many ways how this could be extended, for example by feeding dynamically data updates via another file descriptor on the side, or by specifying custom callbacks.

What kind of features would you be interested in using to enhance your shell scripts with a UI? Let us know in the comments.