- cross-posted to:
- programming@programming.dev
- cross-posted to:
- programming@programming.dev
New favorite tool 😍
As someone who has done way too much shell scripting, the example on their website just looks bad if i’m being honest.
I wrote a simple test script that compares the example output from this script to how i would write the same if statement but with pure bash.
here’s the script:
#!/bin/bash age=3 [ "$(printf "%s < 18\n" "$age" | bc -l | sed '/\./ s/\.\{0,1\} 0\{1,\}$//')" != 0 ] && echo hi # (( "$age" < 18 )) && echo hi
Comment out the line you dont want to test then run
hyperfine ./script
I found that using the amber version takes ~2ms per run while my version takes 800microseconds, meaning the amber version is about twice as slow.
The reason the amber version is so slow is because: a) it uses 4 subshells, (3 for the pipes, and 1 for the $() syntax) b) it uses external programs (bc, sed) as opposed to using builtins (such as the (( )), [[ ]], or [ ] builtins)
I decided to download amber and try out some programs myself.
I wrote this simple amber program
let x = [1, 2, 3, 4] echo x[0]
it compiled to:
__AMBER_ARRAY_0=(1 2 3 4); __0_x=("${__AMBER_ARRAY_0[@]}"); echo "${__0_x[0]}"
and i actually facepalmed because instead of directly accessing the first item, it first creates a new array then accesses the first item in that array, maybe there’s a reason for this, but i don’t know what that reason would be.
I decided to modify this script a little into:
__AMBER_ARRAY_0=($(seq 1 1000)); __0_x=("${__AMBER_ARRAY_0[@]}"); echo "${__0_x[0]}"
so now we have 1000 items in our array, I bench marked this, and a version where it doesn’t create a new array. not creating a new array is 600ms faster (1.7ms for the amber version, 1.1ms for my version).
I wrote another simple amber program that sums the items in a list
let items = [1, 2, 3, 10] let x = 0 loop i in items { x += i } echo x
which compiles to
__AMBER_ARRAY_0=(1 2 3 10); __0_items=("${__AMBER_ARRAY_0[@]}"); __1_x=0; for i in "${__0_items[@]}" do __1_x=$(echo ${__1_x} '+' ${i} | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//') done; echo ${__1_x}
This compiled version takes about 5.7ms to run, so i wrote my version
arr=(1 2 3 10) x=0 for i in "${arr[@]}"; do x=$((x+${arr[i]})) done printf "%s\n" "$x"
This version takes about 900 microseconds to run, making the amber version about 5.7x slower.
Amber does support 1 thing that bash doesn’t though (which is probably the cause for making all these slow versions of stuff), it supports float arithmetic, which is pretty cool. However if I’m being honest I rarely use float arithmetic in bash, and when i do i just call out to bc which is good enough. (and which is what amber does, but also for integers)
I dont get the point of this language, in my opinion there are only a couple of reasons that bash should be chosen for something a) if you’re just gonna hack some short script together quickly. or b) something that uses lots of external programs, such as a build or install script.
for the latter case, amber might be useful, but it will make your install/build script hard to read and slower.
Lastly, I don’t think amber will make anything easier until they have a standard library of functions.
The power of bash comes from the fact that it’s easy to pipe text from one text manipulation tool to another, the difficulty comes from learning how each of those individual tools works, and how to chain them together effectively. Until amber has a good standard library, with good data/text manipulation tools, amber doesn’t solve that.
This is the complete review write up I love to see, let’s not get into the buzzword bingo and just give me real world examples and comparisons. Thanks for doing the real work 🙂
One day, someone’s going to have to debug machine-generated Bash. <shivver>
For maximum efficiency we’d better delegate that task to an intern or newly hired jr dev
Just learn Bash lol
Looking at the example
Why does the generated bash look like that? Is this more safe somehow than a more straighforward bash if or does it just generate needlessly complicated bash?
Yeah that shit is completely unreadable
I doubt the goal is to produce easily understood bash, otherwise you’d just write bash to begin with. It’s probably more similar to a typescript transpiler that takes in a language with different goals and outputs something the interpreter can execute quickly (no comment on how optimized this thing is).
As a long-time bash, awk and sed scripter who knows he’ll probably get downvoted into oblivion for this my recommendation: learn PowerShell
It’s open-source and completely cross-platform - I use it on Macs, Linux and Windows machines - and you don’t know what you’re missing until you try a fully objected-oriented scripting language and shell. No more parsing text, built-in support for scalars, arrays, hash maps/associative arrays, and more complex types like version numbers, IP addresses, synchronized dictionaries and basically anything available in .Net. Read and write csv, json and xml natively and simply. Built-in support for regular expressions throughout, web service calls, remote script execution, and parallel and asynchronous jobs and lots and lots of libraries for all kinds of things.
Seriously, I know its popular and often-deserved to hate on Microsoft but PowerShell is a kick-ass, cross-platform, open-source, modern shell done right, even if it does have a dumb name imo. Once you start learning it you won’t want to go back to any other.
I appreciate you sharing your perspective. Mine runs counter to it.
The more PowerShell I learn, the more I dislike it.As someone who spent 2 years learning and writing PowerShell for work… It’s… Okay. Way easier to make stuff work then bash, and gets really powerful when you make libraries for it. But… I prefer Python and GoLang for building scripts and small apps.
Do you write it for work?
I do. Currently I use it mostly for personal stuff as part of my time spent on production support. Importing data from queries, exporting spreadsheets, reading complex json data and extracting needed info, etc. In the past when I was on DevOps used it with Jenkins and various automation processes, and I’ve used it as a developer to create test environments and test data.
Basically another shell scripting language. But unlike most other languages like Csh or Fish, it can compile back to Bash. At the moment I am bit conflicted, but the thing it can compile back to Bash is what is very interesting. I’ll keep an eye on this. But it makes the produced Bash code a bit less readable than a handwritten one, if that is the end goal.
curl -s "https://raw.githubusercontent.com/Ph0enixKM/AmberNative/master/setup/install.sh" | $(echo /bin/bash)
I wish this nonsense of piping a shell script from the internet directly into Bash would stop. It’s a bad idea, because of security concerns. This install.sh script eval and will even run curl itself to download amber and install it from this url
url="https://github.com/Ph0enixKM/${__0_name}/releases/download/${__2_tag}/amber_${os}_${arch}"
… echo “Please make sure that root user can access /opt directory.”;And all of this while requiring root access.
I am not a fan of this kind of distribution and installation. Why not provide a normal manual installation process and link to the projects releases page: https://github.com/Ph0enixKM/Amber/releases BTW its a Rust application. So one could build it with Cargo, for those who have it installed.
I wish this nonsense of piping a shell script from the internet directly into Bash would stop. It’s a bad idea, because of security concerns.
I would encourage you to actually think about whether or not this is really true, rather than just parroting what other people say.
See if you can think of an exploit I perform if you pipe my install script to bash, but I can’t do it you download a tarball of my program and run it.
while requiring root access
Again, think of an exploit I can do it you give me root, but I can’t do if you run my program without root.
(Though I agree in this case it is stupid that it has to be installed in
/opt
; it should definitely install to your home dir like most modern languages - Go, Rust, etc.)I would encourage you to actually think about whether or not this is really true, rather than just parroting what other people say.
I would encourage you to read up on the issue before thinking they haven’t.
See if you can think of an exploit I perform if you pipe my install script to bash, but I can’t do it you download a tarball of my program and run it.
Here is the most sophisticated exploit: Detecting the use of “curl | bash” server side.
It is also terrible conditioning to pipe stuff to bash because it’s the equivalent of “just execute this
.exe
, bro”. Sure, right now it’s github, but there are other curl|bash installs that happen on other websites.Additionally a tar allows one to install a program later with no network access to allow reproducible builds. curl|bash is not repoducible.
But…“just execute this
.exe
, bro” is generally the alternative to pipe-to-Bash. Have you personally compiled the majority of software running on your devices?
Removed by mod
What are you talking about?
Removed by mod
I like the idea in principle. For it to be worth using though, it needs to output readable Bash.
Why?
Because you still need to be able to understand what’s actually getting executed. There’s no debugger so you’ll still be debugging Bash.
Compiling to bash seems awesome, but on the other hand I don’t think anyone other than the person who wrote it in amber will run a bash file that looks like machine-generated gibberish on their machine.
There’s a joke here but I’m not clever enough to make it.
Pretty cool bug. Looks like a surreal meme
Here’s a language that does bash and Windows batch files: https://github.com/batsh-dev-team/Batsh
I haven’t used either tool, so I can’t recommend one over the other.
The only issue I have is the name of the project. They should have gone with a more distinct name.
I can’t believe they didn’t with go with BatShIt. it’s right there! they were SO close!
I checked the docs, and I’m a bit confused with one thing. They show that you can capture the stdout of a command into a variabe, but they never show stderr being captured. How would that work?
Like this: ‘’’ $mv file.txt dest.txt$ failed { echo “It seems that the file.txt does not exist” } ‘’’
Knowing if a command failed and capturing stderr (which contains stuff like error messages) are not the same thing.
with no support for associative arrays (dicts / hashmaps) or custom data structs this looks very limited to me
Does Bash support those? I think the idea is that it’s basically Bash, as if written by a sane person. So it supports the same features as Bash but without the army of footguns.
A language being compiled should be able to support higher-level language concepts than what the target supports natively. That’s how compiling works in the first place.
I’m a mathematician with very limited programming experience. Can someone explain the significance of this?
Basically dealing with abandoned-by-god syntax and limitations of bash. You can abstract them away!
Why not compile it to sh though.
There is no sh shell. /bin/sh is just a symlink to bash or dash or zsh etc.
But yes, the question is valid why it compiles specifically to bash and not something posix-compliant
There is no sh shell.
lol
Yes, there was the bourne sh on Unix but I don’t see how that’s relevant here. We’re talking about operating systems in use. Please explain the downvotes
It’s relevant because there are still platforms that don’t have actual Bash (e.g. containers using Busybox).
sh
is not just a symlink: when invoked using the symlink, the target binary must run in POSIX compliant mode. So it’s effectively a sub-dialect.Amber compiles to a language, not to a binary. So “why doesn’t it compile to
sh
” is a perfectly reasonable question, and refers to the POSIX shell dialect, not to the/bin/sh
symlink itself.Thanks