Hacker News new | past | comments | ask | show | jobs | submit login
Showing GUIs from Shell Scripts (sixtyfps.io)
165 points by ogoffart 5 days ago | hide | past | favorite | 55 comments

I usually add bottle.py[0] in my project (it's single file!) and add a simple HTML form with a submit button. When I need to show a UI, I start a server, open up the URL and when the form is submitted, I shutdown the server and continue executing the script.

Using HTML means I can start off with plain HTML and no style (except user-agent) and keep building on it (change font, center it in the page, etc.). I can keep HTML, JS, CSS on the same page, add AlpineJS[1] if I need a reactive UI and so on.

The only thing missing is that I can't close the tab using JavaScript when it's finished, so the user (usually me) has to close it himself.

[0]: https://bottlepy.org/docs/dev/

[1]: https://alpinejs.dev

> The only thing missing is that I can't close the tab using JavaScript when it's finished, so the user (usually me) has to close it himself.

how come? doesn't window.close() work for you?

    save(event) {
      ...take the action you wanted...
    <button onclick="(event) => save(event)">

That only works for popup windows (ones created with `window.open()`) [0].

From MDN:

> This method can only be called on windows that were opened by a script using the Window.open() method.

I was unable to get `window.close()` to work on root windows, but your comment prompted me research it again. This seems to work:


[0]: https://developer.mozilla.org/en-US/docs/Web/API/Window/clos...

Related: Gooey[1] for turning python scripts into GUIs

[1] https://github.com/chriskiehl/Gooey

Gooey is amazing. You can go from a command line window to an install wizard type interface in 5 minutes.

The last thing I want in my shell script is to have it depend on a brand-new utility, which is part of the Rust ecosystem that is itself still new and evolving. Shell scripts need to be super stable and portable.

Edit: If I need GUI in my scripts, I'd probablyjust use dialog and other curses stuff.

It's a native program; it's not going to morph out from under you. The Rust build system swears by semver compatibility, and crates.io is a permanent repository; it's not going to stop building. So what critique are you actually making, that {random C++ project} survives?

Also most of the time I work via SSH on remote servers. I very much prefer any TUI over something I need to use X-forwarding for.

I still prefer the plain question and answer approach.

The OpenBSD installer follows it, for example, and makes for a very simple interaction. When SSHing to a remote host, it's quite snappy , and has no drawing overhead.

I mentioned the Gtk-server above. You might be able to use it across an SSH connection even without X forwarding.

Imtui is not the same things as it is a C++ library, so you don't write shell code anymore, you write C++

dialog is an option but is quite limited in what you can do. There are many alternatives, and this is just another one to choose from. Depending on where your script is required to run, a Rust tool might not be a problem. Not all shell scripts need to be super portable.

Yes, you're right about ImTui, removed that line. Disagree about portability. I mean, yes, you could write a shell script targeting even a single specific machine, but generally you want to assume as little as possible beyond a GNU operating system and its common utilities.

Beyond a POSIX operating system and its common utilities.

While it is true that some shell scripts need to be portable, many don't. Many shell scripts are written just to run in one single machine. Or they run in a controlled environment. Maybe even a docker container that provide anyway a set of tools and dependencies.

> cargo install sixtyfps-viewer

I don't believe Cargo install is meant to be used as a general purpose distribution tool; though I know it's tempting to bypass the package manager especially when it's so easy.

From what I understand cargo install is supposed to help around rust ecosystem tooling such as installing clippy, xargo and rls, where cargo has much more context than the package manager.

From the RFC the motivations for `cargo install` existing:

> Simple tasks like installing a new cargo subcommand, installing an editor plugin, etc,


Short of building distribution packages and offering those as binaries for the download, this seems like a simple way to offer a download.

It's not perfect though, and I think we're going to try to create binaries for download alternatively.

That's exactly what distribution package managers are meant for.

I like yad[0] for this. For example, I use it to present a GUI color picker to change/insert colors in Vim (via a plugin called vCoolor[1]). I also use it in some i3/sway scripts that need user input or to show a progress bar.

[0]: https://github.com/v1cont/yad

[1]: https://github.com/KabbAmine/vCoolor.vim

YAD is, in fact, the source of inspiration for this blog post. I seen YAD mentioning and that you can do pretty advanced stuff with it. Since we're developing a GUI framework I thought we could do the same with our viewer utility, and be even more flexible.

I've used wish (https://linux.die.net/man/1/wish) for this in the past and it works pretty well. It used to come installed on many Linux distros but probably does not anymore.

Zenity is also an option.

Both are wonderful options for some use cases. I would also take one of thise approaches for the simple demo in the blog post.

But the system UI that is also linked in there is something that goes beyond what you can do with e.g. zenity.

This kind of puts (almost) all the power of a modern UI description language in reach of shell scripts.

And tksh (shell with tk builtins), which made (makes, if you take the trouble to install it now) it trivial to add a simple GUI to an existing shell script.

Do you happen to know where there's a copy of the source? The stuff on the tcl wiki all seems to be dead and that sounds fascinating to take apart to learn how it works.


There's not really much to it; it's just an example of extending ksh with more builtins, which is simple by design. (I really miss what this did for Sun's dbx debugger — instead of being inside some tool with yet another idiosyncratic command language, your shell just grew commands for interacting with the process being debugged.)

Aha, I shall have a dig through https://github.com/att/ast/tree/master/src/lib/libtksh then.

Thank you kindly.

On Windows, I use the built-in Microsoft HTML Applications (HTAs) to build single-file, double-clickable GUIs in JS. Using ActiveXObject from within your HTA, you can write scripts for pretty much anything on your PC. (So this isn't showing a GUI from a script, but scripting from within a GUI application).

Wow, that's kinda magical. I had no idea that was a thing!

I've started writing a guide about it: https://marksweb.site/hta/ It's still very much work in progress, but maybe it helps if you wanna try developing HTAs.

For simple dialog boxes, Zenity is also an option:


The big advantage of Zenity is that is it installed by default. A lot of other systems have fantastic usability and better options, but they aren't installed on the machine so it's moot.

I used zenity but found yad, mentioned elsewhere, to be AFAICT zenity compatible but with more features.

Tcl/Tk reinvented?

I have been seeing lots of reinventations lately, I guess learning about computer history is not really a thing.

One of the lesson that I believe is being learned is that general purpose programming languages for UIs make it difficult to do tooling, especially with dynamic typing.

This particular approach (.60) is not a general purpose programming language and it's strongly typed.

It's designed for the user interface, not for writing the rest of the program in it.

I feel this is rather different from the tcl/tk applications we used to see?

As Lisp, Smalltalk, Dylan and Postscript have proven during the early days, it is possible.

The problem is that current generations cannot see beyond their vi/emacs CLI setups and are too invested into HTML/CS/JS stacks to see otherwise.

Some quickly picked examples,


"Smalltalk usage for UI prototyping in Thales industrial context"


"Interface Builder's Alternative Lisp Timeline"


Which by the way, makes the binding Objective-C / Smalltalk /Lisp in UI design.

Lost the Smalltalk content on youtube, so


Or Motif's UIL, as if people cried out for that.

it tickles

Very cool project! It's exciting to see two reputable Qt & KDE devs doing fresh stuff. (as a long-time linux user and Qt and KDE hobbyist I recognize their names like a sports fan recognizes their favorite players' names)

thank you :-)

> error: failed to run custom build command for `servo-fontconfig-sys v5.1.0`

Not sure users who prefer a GUI over the command line, would be too happy about having to fix compile errors prior to running the program?

Yes, there should be pre-build binaries of the viewer available.

Right now there is not, but work is being done to cover the common platforms.

The original graphical shell was written by J. Stephen Pendergrast and documented in the book "Desktop KornShell Graphical Programming," ISBN 0-201-63375-2. This book is hard to find.

Pendergrast's shell was included in the CDE standard, directly accesses Motif and X11 primitives, and builds on modern systems.

The source code is in this collection:


it seems like it would be more straightforward to build a gui that invokes your shell scripts, rather than modify your shell scripts to include a gui.

What about dialog, zenity, kdialog?

That works for simple text input stuff, but not when you want a more complex or custom GUI like the second example.

If you need a complex GUI, I guess it's time to ditch the shell script and reimplement it in a higher language...

Why's that? The logic might be easy to do in shell. And if there is an easy way to give a good presentation from your shell script, then let's just use that.

Obligatory mention of Gtk-Server: https://www.gtk-server.org

Can communicate using nine IPC mechanisms AND as a loadable library with a small C API.

Also, if you're running a Gtk desktop, it obviously obeys your Gtk theme.

If you're adding IPC mechanisms to a shell script, seriously consider if you should be writing it in a lower level language, like python or go or rust...

You can use it from whatever you want; it's not just for shell scripts.

Although why you'd go for a lower level language if you don't have to for some specific reason is beyond me. GUIs specifically have been historically very friendly towards very high level languages - see Tcl/Tk.

Also, by your logic, shell scripts should never use pipes; you should always use pipes from Python or Go or Rust. But I suspect that's not how other people usually think.

My experience with anything involving tcl/tk has always been suboptimal.

Also, we're specifically talking about shell scripts.

I'd argue that if you're implementing an entire protocol into a shell script, yes, you should consider more efficient languages. If you're just dumping data into a pipe like you would to std out, sure that's fine.

The key here, at least for me, is complexity. Are you bludgeoning shell scripts into something it wasn't meant for? Is there a better alternative meant to do the thing you're doing?

Well, if you prefer Python, Perl, or Ruby, you can use those fairly easily.

No Python bindings, in 2021 ? That's pretty balsy.

We plan to add bindings to more languages such as Python, Go, and others

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact