Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Bashsimplecurses: Simple curses library made in bash to draw terminal interfaces (github.com/metal3d)
85 points by tambourine_man on July 27, 2024 | hide | past | favorite | 31 comments


There's some quite impressive and interesting bash (and other shell) exploration in the matrix.org "Fun Shell Scripting" room from time to time; usually when someone asks an obscure question and a few people dive down a rabbit-hole.

One oft overlooked feature is bash supports dynamically loadable 'builtins' as shared object modules so it wouldn't take much to create a 'proper' wrapper around libncurses.

Debian and derivatives have the package "bash-builtins" that has a lot of examples including wrapping/implementing many coreutils tools.


A good example for lulz is https://github.com/zevweiss/booze, a FUSE binding for bash.

Aside: I've wondered aloud if we could figure out how to systemically compile coreutils into true bash builtins for performance benefits in nix builds, but someone did rightly point out that builtins can't be completely fungible with a separate process in all cases, especially where stuff like pipelines are involved. I don't recall the exact details and couldn't readily find the conversation but IIRC it had to do with signal handling.

Edit: Found the conversation: https://gist.github.com/abathur/74e7a63b25b7bbd4a6fa9ad7e728...


> One oft overlooked feature is bash supports dynamically loadable 'builtins' as shared object modules

2+ decades of daily bash usage, and TIL...

Any good (short) reads on how ones does this? I can think of a few things that I'd like native in the shell.


It's all in the code - many simple examples to get started

https://git.savannah.gnu.org/cgit/bash.git/tree/examples/loa...


This is cool, I've used curses UIs to build various small things that need to be a) vaguely easy to use (so, complicated CLIs are out. oncalls need to be able to use this at 3am while half their brain is still sleeping) and b) accessible over ssh because we have secure ssh access to these envs but ~nothing else.

So I love TUIs.

That said, I'm always a little puzzled about why people build these libraries in bash. Is it simply curiosity? Maybe, and if so, godspeed.

But if it's driven by pragmatism, let me assure the reader that if there are limits to the extents I will go to get python somewhere instead of writing even a somewhat nontrivial bash script, I have yet to find them. Not only is bash just kind of really annoying to program in, it's also nearly unethical to program in. Let me link the 2 I always link to when someone tells me they're "working on" a bash script.

Steam deleted my entire system (empty variable expansion): https://github.com/valvesoftware/steam-for-linux/issues/3671

Bumblebee deletes /usr due to space: https://www.reddit.com/r/softwaregore/comments/2hsdo6/giant_...

So I warn people: if you use python, you'll categorically avoid being the third entry in my list.


Both of those are examples of known footguns in BASH and it's easy enough to avoid them if you run your BASH scripts through ShellCheck and follow the recommendations.


Python is available virtually anywhere. I'd also not use Bash unless it's a very restricted situation. Every time I'm writing a shell script that's more than a page, a sense of imminent doom starts to dominate my soul.


“Python” isn’t very well-defined. Which version? Which (installed) dependencies?


No it isn't. I don't know what kind of infrastructure you work on but I can't just go installing python on prod servers whenever I want to be able to run some random script.


I think that people that work on RHEL often assume python just "exists" everywhere because DNF has a python dependency, same for Debian, apt and perl.


In Kubernetes, you can attach a debug container with Python to a running pod.

On VM's you can use pyenv for a local Python installation if you don't want to install it globally.

In Docker vanilla, you can run another container with Python that uses the same namespaces (ipc, pid, network) as your other running container without Python.

There are options. If your security team forbids Python for some reason, I would wonder why they are letting systems have bash/curl/etc on them.


Why are you running random scripts on prod servers? ;) :P


Sometimes the only way to investigate a problem. How can you even write a test case if you don't know what's going on?


Python subprocess is terrible. Until they provide a much smoother interface for running other programs, bash will continue to dominate scripting.


Python is not available by default on macOS.


Python also brings a wrapper for curses (atleast under *nix).

Curses in itself needs so much boilerplate that I usually just go to the libraries rich or textual instead.


Zsh users get a bundled curses module; see zsh/curses¹ in zshmodules(1). It is a very thin wrapper, so it works how you'd expect from other uses. There is a tetris implementation using zsh/curses that ships with zsh², and you can use it as a nice comparison to the non-curses implementation that also comes with zsh³.

I've used zsh/curses a few times to hack together little interfaces, and it is quite workable. It makes things far simpler once you start reaching for terminfo's capabilities that require you to think about state too much. A friend of mine wrote a little mblaze⁴ frontend using it, and it felt like using single mailbox mutt with less than a hundred lines of code.

I was expecting the linked project to be a loadable module too given that bash also supports them, but it is actually a little more interesting to look at given it implements a bunch of the behaviour itself on top of tput calls.

¹ https://zsh.sourceforge.io/Doc/Release/Zsh-Modules.html#The-...

² https://github.com/zsh-users/zsh/blob/master/Functions/Misc/...

³ https://github.com/zsh-users/zsh/blob/master/Functions/Misc/...

https://git.vuxu.org/mblaze/about/


I have a fondness for bash abuse and those odd sort of people who get fixated on bash. bed [0] the bash editor is one of my favorite examples, always surprised by how short and concise it is, far from a great editor but a great exercise and I learned a thing or two about the bash way from it.

0. https://github.com/comfies/bed


I've made a similar library called bash-term[1], which is similar, but only has functions for lower-level operations, like moving the cursor to the end of the line, etc. It's also cleaner and has almost no global variables.

[1] https://github.com/bash-bastion/bash-term


If you only need simple dialogs, whiptail is usually installed on Debian-based systems: https://en.wikibooks.org/wiki/Bash_Shell_Scripting/Whiptail


Bash with a #!/bin/bash shebang. Typical GNU cultural imperialism. "Everyone has a Bash and it's always kept in /bin."


And the alternative when you definitely want bash because you've used extended non-posix features /bin/sh is not guaranteed to have?

Without just using #!/bin/sh (or some trick with env that may also not be portable), then having a large fancy function to test for current shell identity and tries to search for & respawn with something else if that does not seem to be suitably compatible?

The project has bash on its name - it is not as if it is pretending to be more generic, or written by someone who has always had bash linked from /bin/sh and knows no better.


Presumably:

    #!/usr/bin/env bash


#! env bash at least makes it path independent. But I think the parent comment is in jest.


If the only purpose of this project is to create windows in Bash one might easily replace it with tmux panes.


This reminds me of something I have always wanted in the UNIX ecosystem:

"topify"

... which is the word I would use to describe a primitive that will take line inputs from stdio and display them in a 'top' style output, presumably with curses.

Maybe there is more complication here than I have thought out but ... if I can output a standard line with columns I have already defined (perhaps in an 'awk' pipeline or whatever) then I would like a way to refresh them, in some order.

I am fairly certain this does not exist ...


You mean "watch"?


There is also viddy¹ for a slightly more featureful watch alternative, if you're open to a new non-default package. Being able to recall old output and search within it can be extremely useful.

Admittedly, it isn't quite a drop in replacement, but the usage is close enough that even aliasing it is unlikely to cause [many] problems.

¹ https://github.com/sachaos/viddy/


"You mean "watch"?"

I'm not sure.

I've been directed to this in the past but I have a vague sense that it didn't do what I was looking for.

I will take another look ...


mprocs is worth checking out!

https://github.com/pvolok/mprocs


This is really cool, thank. After many decades, I’m still on the fence with multiplexers. Mostly because I enjoy native scrolling and copying so much.




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

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

Search: