Bunster: Compile bash scripts to self contained executables
github.com
github.com
It does work - but there are some OS-specific stuff that can still pop up and explode on you. There are different guarantees around open/write on Windows and *nix, and cosmopolitan doesn't 100% paper over those gaping differences. It doesn't change the underlying file locking behaviour of the file system, for example. You can run into thread-time guarantees and other streaming problems, when piping from one thing to another.
Though, cosmo might then run into Windows not being happy with two things attempting to open the same file, if the programmer then attempts to reopen the file. You could do some logic that cancels closing in the thread, and re-hands the handle to the user if the handle still exists, but that might be a little fragile.
To be honest... There may not actually be a good answer that works 100% of the time. Working around the platform might introduce race conditions you absolutely don't want.
That said, in a similar vein, you could probably create a bundler that takes a shell script and bundles it with busybox to create a static program.
So in theory I could build a feature that allows you to ship a self contained executable like you’ve described.
If this is something you’re genuinely interested in and my shell has the right kind of ergonomics for you, then feel free to leave a feature request:
An alternative is to use crunchgen from NetBSD (also included with some of the later BSDs) which crunches full-featured, source tree versions of multiple utilities in a single, static binary. What busybox refers to as a "multi-call" binary.
It will be larger than busybox of course. I get evertyhing I need in a binary less than 5M.
> Standard library: we aim to add first-class support for a variety of frequently used/needed commands as builtins. you no longer need external programs to use them.
That's not going to be an easy task, and would basically entail porting those commands to go.
So instead, at some point I change the language entirely and write a utility in python/lua/c/whatever other language I want.
As time goes on, my limit for "sufficient complexity" to justify leaving bash and using something like python has dropped radically. Now I follow the rule that as soon as I do something "nontrivial", it should be in a scripting language.
As a side-effect, my bash scripting skills are worse than they once were. And now the scope of what I consider "trivial" is shrinking!
I'm using it daily for many years now and it does exactly what I expect it to do.
Now I'm a little concerned by the end of your message because it could make its usage a bit trickier...
My main usecase is to curl the raw discord.sh file from GitHub in a Dockerfile and put in in /user/local/bin, so then I can _discord.sh_ anytime I need it. Mostly used for CI images.
The only constraint is to install jq if it's not already installed on the base image.
Switching to Go or C would make the setup much harder I'm afraid
If you don't want to watch video , then I can link the tool it uses https://github.com/igor-petruk/scriptisto/wiki/Writing-scrip...
to quote from the page
With scriptisto you can build your binary in an automatically managed Docker container, without having compilers installed on host. If you build your binary statically, you will be able to run it on host. There are a lot if images that help you building static binaries, starting from alpine offering a MUSL toolchain, to more specialized images.
Find some docker-* templates via scriptisto new command.
Examples: C, Rust. No need to have anything but Docker installed!
Builds in Docker enabled by populating the docker_build config entry, defined as such:
Also I am watching the video again because I had viewed it a looong time ago !
Works great. I use this instead of pipx.
On the concern of it would be harder to setup, I think it would be easier in fact, you would simply curl the Go or C statically generated binary to your path and would alleviate the need for jq or curl to be installed alongside.
I think the reason I haven’t made the switch yet is I like Bash (even though my script is getting pretty big), and in a way it’s a testament to what’s possible in the language. Projects like https://github.com/acmesh-official/acme.sh really show the power of Bash.
That and I think the project would need a name change, and discord.sh as a name gets the point across better than anything I can think of.
In that case yes, if it allows you to keep the project going, that's great!
Also, using a better shell language can be a huge productivity (and maintenance and sanity) boon, making it much less “write once, read never”. Here’s a repo where I have a mix of fish-shell scripts with some converted to rust scripts [1].
Yes, if you're going to import numpy or pandas or other heavy packages, that can be annoyingly slow.
But we're talking using Python as a bash script alternative here. That means (at least to me) importing things like subprocess, pathlib. In my experience, that doesn't take long to start.
$ cat helloworld.py #!/usr/bin/env python3 import subprocess from pathlib import Path print("Hello, world!\n")
$ time ./helloworld.py Hello, world!
real 0m0.034s user 0m0.016s sys 0m0.016s
34 milliseconds doesn't seem a lot of time to me. If you're going to run it in a tight loop than yes, that's going to be annoying, but in interactive use I don't even notice delays as small as that.
As for packaging complexity: when using Python as a bash script alternative, I mostly can easily get by with using only stuff from the standard library. In that case, packaging is trivial. If I do need other packages then yes, that can be major nuisance.
It’s what makes shell scripts so fast and easy for a lot of tasks.
I would like it if Python just had a sane nice HTTP client built in, but it can also just shell out to curl.
It certainly takes more effort for this to be a problem on modern x86 systems.
You know, assuming they transpile well, I haven't tried a solid one yet.
I wonder if kernel code rewrites in rust with Llama (obviously reviewed are up to snuff.
writeShellApplication {
name = "show-nixos-org";
runtimeInputs = [ curl w3m ];
text = ''
curl -s 'https://nixos.org' | w3m -dump -T text/html
'';
}
writeShellApplication will call shellcheck[1] on your script and fail to build if there are any issues reported, which I think is the only sane default.[0]: https://nixos.org/manual/nixpkgs/stable/#trivial-builder-wri...
If you're reading this and wondering how you can use this for yourself?
You don't need nixos at all. You can install nix on any linux-like system, including on MacOS
How's nix these days? How long would you expect someone with years of Linux management experience (bash, ansible, terraform, you name it, either onprem or on cloud) to get comfortable with nix? And what's would be the best roadmap to start introducing nix slowly in my workflow?
# shellcheck disable=SC2086
which remain valid within that block.
Of course, disabling the linter should be done with deliberation...
Because if I wanted a portable shell script, I’d just write shell and check if something is executable in my path.
This just looks like Nix-only stuff that exists in an effort to be ultra declarative, and in order to use it you’d need to be on Nix.
(I'd say it's overkill for your example here, but it blocks on missing dependencies and can support tricky cases such as modular shell libraries that expect different implementations of the same command.)
Bringing this into your system seems like a huge liability.
The syntax of shell scripts is terrible, but we write it to do simple things easily without needing more external tools.
git-bash on windows is generally good enough to do the kind of things most shell scripts do.
This tool feels like the worst of both worlds: bash syntax + external dependency.
Because then you could compile something like
#!/usr/bin/env bash
eval “$@“
And get a statically compiled bash!All it does is evaluate the expression you pass in as arguments.
./evalme.sh echo hello world
The joke being that if you could transpile this evalme.sh script to a static binary, you’d effectively have a static version of bash itself (transpiled to Go).So if you save the file as foo.sh and add it to your PATH. You could run:
$ foo.sh 'date ; ls ; foo=bar ; echo "Hello $foo"'
Or really anything you'd like as the argument is treated as a bash script.NOTE: The original comment had the #! of the shebang backwards (as !#) due to a typo.
That said - this is a neat project and I've seen plenty of "enterprise" use-cases where this kind of thing could be useful.
Given the great diversity of shell scripting needed (even if just bash) across different variants of Linux and Unix and different platform versions, debugging the resulting transpiled executables is not something I'd be keen to take on. You'd want to be an expert in the Go ecosystem at minimum, and probably already committed to moving your utility programming into Go.
My gut feeling says no. Unless I am missing something.
Support for that makes me sad. It's antithetical to everything FOSS is.
Here's some FOSS just for you:
/* Copyright (c) 2025 xyzzy_plugh all rights reserved.
Usage of the works is permitted provided that this instrument is retained with the works, so that any entity that uses the works is notified of this instrument.
DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
*/
if(time(NULL) > 1767225600) exit(1);Still, I can see this being really handy for people who don’t speak Go or Rust but want to throw together a quick-and-dirty shell script and still need a standalone binary.
By the time I read up on why that didn't work and how to "fix" it, I decided it was a bad idea and tried something else.
But if you have to run n processes, much better to run them in a single pipeline like that.
(Source: I’m a shell developer. Fish-shell ftw!)
The only reason to use shell in the first place is because I can't use a binary compiled from a sane language.
This... Wow. This is like not having your cake and not eating it.
The shitness of Bash combined with the non-portability of binaries! Sign me up!
It's the opposite of https://amber-lang.com/ which tries to (not sure it succeeds) provide a sane language with the portability of shell (ignoring Windows).
That's a sensible project. This is just... Why does this exist?
Powershell written for Windows 2016 is likely to work fine on 2019/2022/2025.