I don’t think these issues would necessarily be solved at all by waving a hand and replacing it with similarly complex build tools. Bazel, for example, can be a daunting tool to fully grasp. Any tool used should be well understood. Easier said than done of course.
And shell has a lot of footguns.
As long as you apply the same standards to what seems to be everyones darling: Javascript.
Javascript has the same amount of footguns as PHP and Bash but has gotten away with it by being cute (and having a whole menagerie if support tools around it to make it possible for ordinary people to write workable code in it).
(Yes, I am qualified to rant about Javascript BTW. I wrote a working map rendering system with pan and zoom and automatic panning based on GPS location using ECMAScript and SVG back in the spring of 2005. I think roughly half a year before Google Maps became public. Back before all the modern JS tooling existed. All I had was JEdit with syntax highlighting. Perl at least let me put breakpoints in my code even back then.
And yes, I have written more JS since then.)
Now you can at least just stick to React and TypeScript and bundle it using Webpack and have months of relative sanity between each time you have to throw something out and replace it.
-> REPL essentially for free (the language IS a REPL)
-> enormous installed base
-> No compilation (well, unless you have something--like autotools--using shell as essentially a transpilation target)
-> No need for "libraries" in most cases: the ordinary CLI that $vendor already ships can be used right away, with no need for a custom SDK for whatever "real" language you would otherwise be using. For example, if you are already familiar with the "aws" CLI program, it's trivial to treat it as an "API" for a quick shellscript instead of needing to dig into the boto3 docs to do something equivalent the "right" way.
-> Pretty good integration with standard *nix facilities (redirecting STD{ERR,OUT}, checking existence of files/pipes, checking/setting exit codes, etc.)
That said, what can help drastically here are well-defined best practices and conventions built into the language which, admittedly, bash really doesn’t have.
- Mutating default arguments to functions, so subsequent calls have different behavior
- Somewhat particular rules around creating references vs copies
- Things that look like lambda captures but aren’t quite
- Bash: installed everywhere you want to work (yes, who actually wants to work on Windows ;-)
- C/C++: when speed/size matters there was no alternative except Assembly until recently
- Javascript: until recently this was the most sane option for client side code on the web (Active X and Java applets existed yes but managed to be even worse.)
- PHP: Low cost hosting, Function-As-A-Service way before that became popular, shared nothing architecture, instant reload for local development bliss
- cannot know which object attributes are private or public (and some classes use settable properties so you can't say "just don't set any attributes on non-dataclass objects")
I might agree with "it's not hard to learn it", but I don't agree with "it's not hard to remember it".
I really don't understand this point, its a script language, how old is it doesn't make any difference. I've come accross some Powershell scripts that were unreadable down to its verbosity with certain things, and if you don't already know all the flags and options for it, it's hopeless to try and understand.
Both serve a purpose, neither are 'evil'.
When you use long options in bash (scripts), it becomes very readable, but it's not a widespread practice. I always use long options while writing scripts.
Consider these two examples, which is very straightforward:
- curl -fsSL $URL | bash
- curl --fail --silent --show-error --location $URL | bash
The second one almost "talks you through".
It's true that Bash and Perl has one of the most contractible syntax around, but it's not impossible to make it more understandable.
However, these parts of codebases are considered "supportive" and treated as second class citizens, and never receives the same love core parts of the codebases enjoy. That's a big mistake IMO.
When you make something more readable all around, hiding things becomes harder exponentially.
I challenge you to find a single easily readable >100 line bash script and link it here (I do think small scripts can be fine).
I may add more if I have time today.
Who says I blindly curl2sh these scripts? I download them, read them and understand what they do before running them actually.
Long options make obscure command lines readable and understandable, actually, and if you vet them, you understand what they are doing.
Short options make things harder because I need to open the man of the command to understand what it is doing.
You don't have to do everything blindly as the quick start documents outline.
Also, Python build scripts can be living hell too, full of dancing devils that could be introducing backdoors left and right - just look at your average Conan recipe, particularly for larger/more sensitive libraries, like OpenSSL or libcurl.
And you can't really name such small functions well anyway, not when they're broken down for the sake of being small. Case in point, some build script I saw this week had function like `rename_foo_dll_unit_tests` calling `rename_foo_dll_in_folder` calling `rename_foo_dll` calling `rename_dlls`, a distinct call chain of four non-reused functions that should've been at most two functions.
Are all Python build scripts like that? Not really. It's just a style I've seen repeatedly. The same is the case with inscrutable Bash scripts. I think it speaks more about common practices than the language itself (notwithstanding Bash not really being meant for writing longer programs).
The way it works is that you can provide "recipes", which are Python scripts, that automate the process of collecting source code (usually from a remote Git repository, or a remote source tarball), patching it, making its dependencies and transitive dependencies available, building for specific platform and architecture (via any number of build systems), then packaging up and serving binaries. There's a lot of complexity involved.
Here are the two recipes I mentioned:
libcurl: https://github.com/conan-io/conan-center-index/blob/master/r...
OpenSSL v3: https://github.com/conan-io/conan-center-index/blob/master/r...
Now, for the sake of this thread I want to highlight three things here:
- Conan recipes are usually made by people unaffiliated with the libraries they're packaging;
- The recipes are fully Turing-complete, do a lot of work, have their own bugs - therefore they should really be treated as software comonents themselves, for the purpose of OSS clearing/supply chain verification, except as far as I know, nobody does it;
- The recipes can, and do, patch source code and build scripts. There's supporting infrastruture for this built into Conan, and of course one can also do it by brute-force search and replace. See e.g. ZLib recipe that does it both at the same time:
https://github.com/conan-io/conan-center-index/blob/7b0ac710... -- `_patch_sources` does both direct search-and-replace in source files, and applies the patches from https://github.com/conan-io/conan-center-index/tree/master/r....
Good luck keeping track of what exact code goes into your program, when using Turing-complete "recipe" programs fetched from the Internet, which fetch your libraries from somewhere else on the Internet.