The bash book to rule them all
fabiensanglard.net
fabiensanglard.net
The existence of zsh makes it all a pretty unsatisfactory situation currently. (Btw re. my own level I know the answer to most of the questions posed in the article).
I'd be fine learning either bash or zsh to an advanced level, but learning both to an advanced level sounds bonkers. So I've vaguely come to the conclusion that perhaps that means learning zsh well as a command line tool, and then limiting ones shell scripts to a sane subset of bash that is sufficiently small that you don't need to fully know advanced bash. But then, I don't actually like learning advanced zsh. It seems like a silly language full of completely ad-hoc syntax. Nevertheless, I do use zsh as my shell, I think mainly because tab completion is better.
(I went heavily into nushell, but at the moment it's too different from what one's colleagues are using so it can only be an auxiliary to POSIX shells, and I decided it was a time sink I couldn't afford.)
Advanced Bash-Scripting Guide <https://tldp.org/LDP/abs/html/abs-guide.html>
Bash Guide for Beginners <https://tldp.org/LDP/Bash-Beginners-Guide/html/Bash-Beginner...>
An interactive shell can be a login-shell or a non-login-shell. A login-shell is what you get when you login at one of the virtual terminals of a linux machine. A non-login-shell is a shell started after you logged in (eg. clicking your console-icon in a graphical desktop environment).
An interactive bash will read and execute `bash_profile` (Actually, it will try to read `profile` first, for historic reasons) when it is a login shell, and `bashrc` when it is not.
However, the difference is moot on most systems, since this is what you will probably find in most `~/.bash_profile` files these days:
[[ -f ~/.bashrc ]] && . ~/.bashrc
aka. all interactive shells, no matter if they are or aren't a login shell will just read `.bashrc`For completeness sake: A shell run via `sshd` is technically not an interactive shell, as it is started by the ssh-daemon. However, bash behaves like an interactive non-login shell in this case and reads `bashrc`.
Also for completeness sake: All the files mentioned can be system-wide under `/etc/FILENAME` and user specific (`~/.FILENAME`). Bash first reads the files in `/etc`.
The behavior is documented in the manpage `man bash`, under the section `INVOCATION`.
A shell can be login and non-interactive.
This happens e.g when starting a session from a X session manager. Subsequently a terminal such as Xterm starts non-login interactive sessions, inherits stuff like env vars like PATH from the login shell, and is only concerned with setting up the additional interactive stuff.
Similarly doing ssh <host> <command> starts a non-interactive login shell.
> However, bash behaves like an interactive non-login shell in this case and reads `bashrc`.
IIRC nope: distros such as Debian often have bashrc source bash profile (or the other way around, I can't recall) which has me irate to no end+. They even have some TTY dependent stuff in profile which spits out some error in some cases when no TTY is allocated because heh not interactive.
+ I took great length to have my rc and profile properly separated because it's that much faster not to source the unneeded stuff (at the cost of having to logout to apply login stuff) https://github.com/lloeki/dotfiles
Interesting, is there a source for this? Genuinely interested, because the manpage leaves this part a bit vague:
A login shell is one whose first character of argument zero is a -, or
one started with the --login option.
(...)
Bash attempts to determine when it is being run with its standard input
connected to a network connection, as when executed by the historical
remote shell daemon, usually rshd, or the secure shell daemon sshd.
If bash determines it is being run non-interactively in this fashion, it
reads and executes commands from ~/.bashrc, if that file exists
and is readable.
Sadly, the manpage for sshd also doesn't mention how exactly the users shell is invoked. It does say however: After this, the client either requests an interactive shell or
execution of a non-interactive command
...which I took to understand that the shell dows in fact run as an interactive shell.> IIRC nope: distros such as Debian often have bashrc source bash profile
Well, these are distro dependent things. Since I am not on Debian, I am just refering to the manpage.
ssh user@host export
vs
ssh user@host --> export
or
ssh user@host bash --> export
But it's not sshds job to specify how either shell type is requested.Hmmm....I'm a bit confused by that one. Why is the program that started the shell an important consideration as to whether it should be considered interactive or not? Shouldn't it just be how the shell is most likely to be used?
Are shells started by `xterm` (and similar) "technically" interactive? What about shells started by `screen`/`tmux`? What makes them different to, or the same as, `sshd`?
From the manpage:
An interactive shell is one started without non-option arguments
(unless -s is specified) and without the -c option, whose standard
input and error are both connected to terminals (as determined by
isatty(3)), or one started with the -i option.
Technically, the shell isn't connected to a terminal when started by sshd but to the ssh connection. So yeah, from the point of view of the user, it is absolutely interactive, but not from the point of view of bashs internal logic.https://i.pinimg.com/736x/13/be/5b/13be5b89e662930a2b2dc1573...
I don't really get where the trend of making software books with animals on the cover originates from, but the parodies are fantastic.
> The original cover art consisted of animal designs developed by Edie Freedman because she thought that Unix program names sounded like "weird animals".[2]
Realistically, starting with the POSIX shell, most commonly seen as Debian dash, is the best introduction. Knowing this standard (and what is not in it) will let you write highly portable scripts.
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V...
From here, moving to a text on the 1988 version of the Korn shell is a conservative approach to extended shell syntax (as ksh88 predates the POSIX shell). Korn's own first edition is not a bad place to start.
https://www.amazon.com/KornShell-Command-Programming-Languag...
The ksh88 syntax also addresses mksh directly, the Android system shell.
Taking this route to bash will be more fruitful than unlearning what these other branches of the shell do not support.
However, I would put using ShellCheck as the single most important way to improve your shell scripts
I don’t mean to bash on SO, it’s really valuable sometimes. But corporate culture (faster is always better) and a new breed of programmers that don’t really care, have left us with a big part of the profession that are unable to produce anything new, or solve any unique problems.
It does feel like the proportions might be changing and the quality of software is trending downward, but I think you have it right that the risk of programmers being too "GPT-reliant" is the continuation of a long, intergenerational pattern.
this is something i get jealous of older programmers who grew up on old computers, with printed manuals...when languages were smaller, and the scope of programs were also smaller...and didnt require external libraries.
Now, it is kinda expected that programs support "text" - non-lgc alphabets, context-sensitive collations, ligatures and cursive text, mixed bidirectional text, combining characters, input method support, locale-dependent string interpolation logic.
And one doen't simply handle all of that, not without bolting something else in your program that is probably larger that your program.
And that isn't even instants in time; those are much harder to handle correctly all the time.
For me, the alternative to using ChatGPT to figure some weird piece of Bash trivial out isn't doing the work myself, meticulously and at great length. It's losing interest and not figuring that thing out at all.
GPT and SO can help you make a deadline today, and we all may use them now and then, but consistently relying on them steals essential opportunities for professional growth.
A journeyman woodworker who just asked somebody else to perform all his tricky jigsaw cuts is going to have a hard time developing the muscle memory and intuitions that mark mastery of the craft.
Several times, I had to spend hours to get a .bat script working. Hopefully, it will get better in the future.
I like this idea. Definitely gonna steal it.
I love that "extensions" can be implemented just by writing a couple extra words.
I use LLMs for the latter, and they often do a great job and save a lot of time looking up individual flags, concepts, etc.
As can I. I recently broke my years long streak of not deleting something by accident with an errant bash command.
Just because a tool has the potential for a negative outcome doesn't mean it shouldn't be used. It just means appropriate caution should be used as well.
LLMs fill in the blanks when left to synthesize a response from a prompt as opposed to translating a response from a prompt. These synthesized responses, aka hallucinations, are predictable in nature. Quotes, titles of books, web page links, etc.
Conversely, providing an LLM with all of the facts necessary to complete a response will result in few to no hallucinations.
For example:
Select name and row_id from table1 joined on table2 on table1_id.
This will never return "DROP table1;". It will basically only ever return something very close to what you want.
A LLM will give you the highest likely suggestion. If that happens to be a DROP, it will not stop.
Now that is of course going to be extremely unlikely in your example. What is more likely though is that your SELECT may include a sql injection vulnerability, even more so once your prompts get more complex. The chance of that happening or not, is completely random from a users point of view. Are we going to blame the user for not providing the requirement “without vulnerabilities”? Even if they did, it’s not sure to be fulfilled.
In this parent case, the scenario was inverted. Given a sql query, will gpt explain if it has vulnerabilities or not? Will it even explain the gist of it correct? Who knows if it will hallucinate or not?
As will answers from stackoverflow, always read the comments, always review yourself.
Use gpt all you want. I do it it myself, it’s great for suggestions. Just think that using gpt to explain things you don’t understand and can’t verify easily, can be risky. Even more so in bash where the difference making a destructive command can be a lot more subtle than select vs drop.
The OpenAI API now has support for deterministic responses.
There you go, the burden of proof is on the accuser.
If I were to state “you can never ride your bicycle to the moon”, you could easily say, well, there is a remote possibility, and then force me to prove that there actually is no remote possibility, well, you would clearly see the problem.
I’ll state it again: you will never ride your bicycle to the moon and ChatGPT will never return “DROP table1;” in response to the aforementioned request. It might not be correct, but it won’t be wildly off target like is flippantly suggested in these forums for populist appeal.
My entire point was that hallucinations are not random. If you craft a query that reduces the task to mere translation then you will not get some wildly incorrect response like you would if you asked for quotes from War and Peace.
I’m pretty much convinced that most of the shade against LLMs from developers is motivated more by emotion than reason because this stuff is easily verifiable. To not have realized this means approaching the tools willingly blindfolded!
If I encounter a new unknown command and ask chatgpt to explain it. For me, it is entirely unpredictable if the answer will be 100% correct, 95% correct or complete mansplaining bullshit.
Even if it may be close to the truth, with bash the difference between a 95% answer and a 100% answer can be very subtle, with seemingly correct code and seemingly correct explanation give very wrong end result.
https://cookbook.openai.com/examples/deterministic_outputs_w...
Now go find some instances where someone is presented with "rm -rf /" or "DROP table1;" when otherwise expecting a response to help with non-destructive commands!
For me, it is entirely unpredictable if the answer will be 100% correct, 95% correct or complete mansplaining bullshit.
Please, show me some evidence of this variance because it is either a bold or ignorant claim to say that the outputs are wildly unpredictable. 100% true vs "complete mansplaining bullshit". Run the numbers! Do 10,000 responses and analyze the results! Show me! I am completely unconvinced by your arguments based on direct experience with reality. You can easily change my mind by presenting me with reproducible evidence to the contrary of my beliefs and experiences.
Even if it may be close to the truth
This is just a classic motte-and-bailey fallacy... let me explain! The bailey is the claim that the outputs are "complete mansplaining bullshit", which is very hard to defend. The motte that you retreat to, "close to the truth", is exactly what I'm saying for prompts that are more of a translation from one language to another, English to bash, English to SQL, etc.
I have never claimed it would be 100% correct, just that the hallucinations are very predictable in nature (not in exactness, in nature). Here's an example of the kind of error:
Select name and row_id from table1 joined on table2 on table1_id.
SELECT table1.name, table2.row_id
FROM table1
JOIN table2 ON table1.table1_id = table2.table1_id;
Well, that should obviously be table1.row_id in the SELECT right? And I guess not super clear from the instructions, but standard that the JOIN should be table1.id Oopsie! Is it valid SQL? yes! Is it "complete mansplaining bullshit". Not. Even. Remotely.Anyone who does that now would already have done it from random Google results anyway.
Or `chown -r` or was it.. `chown -R`
For tasks you do regularly, it's worth the investment to learn.
But there is so much to know one short life
I use Perl, now, for shell scripts. Long before LLMs I decided I could not learn another syntax when Perl was 99% as good
Same reason I have not learnt Sed and Awk.
Once I write the document string of the function I want it gets it right faster than anyone I know.
"How do you pass a parameter to a Bash script so that the script will exit with an error if it's not passed?"
I ran this through ChatGPT and I could not get it to give ${1:?} or any variation of that syntax as an answer. So now I also have a way to filter candidates who are leaning on the LLM during the interview process.
Because without checking `man` or stackoverflow (or leaning on ChatGTP) my first response would be to go with `if [ $# -lt 1 ]; ...`. This has the advantage of being pretty readable, and while I've been doing shell scripting for long enough to consider myself reasonably competent at it, I'd have to refer to the man page to be sure what `${1:?}` did.
The substance of the first answer:
#!/bin/bash
# Check if the first parameter is not provided
if [ -z "$1" ]; then
echo "Error: Parameter not provided."
exit 1
fi
The snippet precedes the true statement:> This checks if the first parameter (`$1`) is empty.
But what happened to the supplied task? It was stated and echoed as:
> Anonymous: ...if it's not passed?
> ChatGPT: ...if a specific parameter is not passed...
> ChatGPT: ...if the parameter is set.
The second answer:
#!/bin/bash
: ${1?"Error: Parameter not provided"}
This is correct. But the explanation is not:> ...and the `${1?...}` part checks if the first positional parameter (`$1`) is unset or null.
--
(the most succinct possible idiom is `#!/bin/bash -u`)
The goal of a DevOps engineer should be to write maintainable code so that a junior can come in and tell what it does immediately.
As another commenter said, my answer would be: `[[ $# -ne 1 ]] && exit 1`. That's readable and understandable to anyone who has a basic understanding of bash scripting.
But I also used bash for 15 years before that, and I hardly used the bash manual. I got by with a minimal / sane dialect, and I read a few books about Unix, and one about POSIX shell (the latter is also "meh").
Now that I've read almost all of the bash manual, I'd say it's not really a special document. It's fine, but it's not complete, and I wouldn't say it's particularly well written. It lacks examples.
--
The main recommendation I have for anyone who wants to learn bash is to learn Unix and C. Learning the underlying model explains many things, explains the bad error messages, and makes it easier to use.
https://www.oilshell.org/blog/2020/04/comics.html - Three Comics For Understanding Unix Shell
So yeah I don't think "learning shell" or "learning bash" is actually a great goal -- it's part of the operating SYSTEM, and you want to learn the OS, and its philosophy.
related - https://www.oilshell.org/blog/2021/01/philosophy-design.html - Unix Shell: Philosophy, Design, and FAQs
--
Probably the most useful part of the bash manual is the acknowledgement that there's a lexing design bug with [[ and regular expressions.
It's better to make the regex a separate var, like
pat='[[:digit:]]+'
if [[ $mystr ~= $pat ]]; then ... fi
... than to inline it, because bash does funky stuff when you inline it. It confuses regex metachars and bash metachars.It's trying (and failing) to make regexes syntaically part of the bash language, but it's better to treat it like Python, where Python syntax and regex syntax are separate.
That doesn't mean it's a pleasant or even good read. It's terse, technical and descriptive. It's a users manual, not a textbook, and not a tutorial.
But it's complete, explains everything, it's free, comes with bash, and is searchable ;-)
I have spent a lot of time in there, usually when debugging or extending old shell scripts.
That said, I think with bash (and anything with a man page more than 5 pages long - "screen" and "lsof" for example) it's worth just doing a quick skim of the entire man page once every 5 or 10 years - sure, most of it will be "yeah, I know that", and a bunch will be "... who asked for that? why do we even have that lever?" but there will be a few things that fix something that's annoyed you for years, and a few things that you'll ignore and then 6 months later you'll say "wait, I read something about this" and go back and fix the problem.
(Reading the changelogs of your primary tools is also smart, and I'll admit I pretty much only do that when looking at security changes, or when looking at a weird behaviour change between releases and trying to figure out what the intent was - not that I recommend that part per se, you just become the greybeard everyone comes to with weird questions :-) Most recently, bash pipeline tail-exec...)
Once you've read it, you don't need to Google anymore. You just open up the man page to the relevant section and see all the context, rather than just one answer to one question.
You need to fully understand man before reading the man bash page. Here:
https://man7.org/linux/man-pages/man1/man.1.html
but before that are you reading that on chrome? Have you read the chrome documentation?
a rising tide lifts all ships but bash is the mooring block.
trying nushell next, it looks very promising.
- Jeffrey Snover, Powershell Inventor.
https://evrone.com/blog/jeffrey-snover-interview
Literally designed not to copy bash.
The Get-Help command is super useful, with the option to show examples (-Examples).
Consistency is encouraged because every PowerShell command is the combination of a verb and a noun. The verbs are standardised and you can get a list of supported verbs using Get-Verb. Nouns are free to choose.
There is also Get-Command which gives you a list of available commands in your current shell. You can import modules in the shell which will give you access to extra commands. Get-Command supports the parameters Module, Verb and Noun to filter commands. This allows you to fairly easily discover commands that might be usefull to you.
The Get-Alias command will show you what aliases are defined in your shell. This can sometimes be confusing as some of the default aliases look like Linux/UNIX shell commands.
Creating a PowerShell module is also not that hard. When defining a PowerShell command, it is for example very easy to limit the values for a certain parameter and that in turn hooks in into the completion functionality. The completion functionality is available out-of-the-box for every PowerShell command available, including the ones that you create yourself.
My main OS is Linux, but I do work a lot with Windows systems (I develop in C#). I've used bash a lot, but I also learned PowerShell because that is simply the way to go on Windows systems. I like PowerShell, it has a lot of nice features and it is easy to work with. I find it a lot easier to program extra functionality in a PowerShell module compared to defining extra functions in bash. As a C# developer, PowerShell basically also gives me access to any C# class available by default in .NET. It is even simple to load a class from a third-party assembly, and even to compile C# code on the fly. In short, I can do whatever I want in PowerShell a lot easier than in Bash.
Note that that does not mean that I no longer use Bash. It depends. My default shell on linux is bash. When I need a one-liner to do something, I will first reach for bash. It is only when I need a longer script that I will reach for PowerShell. For example, I need to read a json file, manipulate the json structures and write the data back out. That is something I would do in PowerShell. For a build script that is simply a sequence of steps, I would go for bash, even if it involves the use of jq for json for example. And obviously on Windows, my default shell is PowerShell. Even though I have used cygwin/ming before, I would not do that if I can avoid it... there is really no need to try to run bash or anything else on Windows when you have PowerShell.
In the case of ksh88, it was able to be compiled into a 64k text segment which was the maximum allowed on Microsoft XENIX running on an 80286.
This is a place that Powershell cannot go.
If I were doing stuff with Windows registries, I might use PowerShell, but I don't. I use Unix.
One is not a substitute for the other -- it's both the language AND the "bindings" that count. bash runs on Windows, and PowerShell runs on Linux, but you lose a lot of "enviroment" in both cases.
I wrote about this distinction here - https://www.oilshell.org/blog/2023/06/ysh-design.html - Oils Is Exterior-First (Code, Text, and Structured Data)
In those terms, I say PowerShell/nushell are "interior-first", while bash and OSH/YSH are "exterior-first". It makes a big difference when using them.
pwsh reinforces pretty much the same* thing every time it's used, the more you learn the more you can do with every command, even ones you haven't used yet.
same subject to some base-level provided by the module. i.e. the active directory cmdlets have their own dsl inside -filter because it is a different thing. It's very analogous to `a = sql.cmd('SELECT ...').map(etc...)`. you can, you shouldn't, but maybe its fine. It's up to you.
I think there will always be a place for something like bash pipelines, where the handoff is just a bunch of bits. Some work is all about discovering the structure of your data: you can't have tools that already know it.
But that's not the majority of work these days. Having the handoff be just bits is an elegant solution to the tower-of-babel problem, but it would probably be ok if we spent more time in structured-mode and only leaned into that solution when it was specifically called for.
The problem is that there's no intrinsic structure to data, just useful fictions. This makes structured-mode necessarily opinionated, which means that the ecosystem will always be fragmented: bash and zsh are friends. Powershell and nushell are rivals.
$ echo 25 | pwsh -c '$input-replace"\d",{2*"$_"}'
410
$ echo 25 | perl -pe 's/\d/2*$&/eg'
410
``` PS> $temp:pwsh_out = 10000
PS> /bin/cat /tmp/pwsh_out
10000
``` $ echo ''''
PS> echo ''''
'
``` PS> $Y = { param($f) . { param($x) . $x $x } { param($y) . $f { param($x) . (. $y $y) $x }.GetNewClosure() }.GetNewClosure() }
PS> $fac = & $Y { param($f) { param($n) $n -lt 2 ? 1 : $n * (. $f ($n - 1)) }.GetNewClosure() }
PS> & $fac 5
120
``` PS> gv -v|% m*d|% t*
gv -v|% m*d|% t*
PS> &($x={"&(`$x={$x})"})
&($x={"&(`$x={$x})"})
$ bash
$ eval ${x='echo eval \${${x@A}}'}
eval ${x='echo eval \${${x@A}}'}
```bilingual pun,
.ps1 .pl
1 1
{1} {1}
end {1} sub {1}
{end {1}} {sub {1}}
&{end {1}} &{sub {1}}
``` awk -e 'BEGIN { printf "3\n" }'
perl -e 'BEGIN { printf "3\n" }'
ruby -e 'BEGIN { printf "3\n" }'
pwsh -c 'BEGIN { printf "3\n" }'
``` $ time ...; time ...; ....
real 0.00 ...
real 0.00 ...
real 0.03 ...
real 0.22 ...This means it's either
- Some "Open Core" bullshit with the secret sauce conveniently tucked away in some proprietary blob or restrictive license submodule
- Has a build process so convoluted and mystery-meat-dependency filled it's not worth to bother with.
- Has so many anti features it would require an extensive patchset (like ungoogled-chromium) to fix.
So it might be interesting technology, but it's not something I'd deploy by default to every server and expect to work in 5 years time.
Oh, heh, also https://github.com/PowerShell/PowerShell/blob/master/docs/bu... the build script is written in PowerShell, so there's a bootstrapping problem :-) (Debian has solved those before of course, but with community sentiment like the above maybe noone is motivated to bother.)
Unless I am a windows administrator, my question is: Why should I?
There is literally ZERO reason for me as an administrator *nix machines to ever touch pwsh.
> but there's some genius in there
I am sure there is. But it's buried very well under layers upon layers of deep integration with windows and .NET, the attempt to shoehorn a character-based shell into working with objects somehow, and a syntax that rivals enterprise java in its verbosity.
> nd specifically the help system is categorically better
Is it? Why? Man pages, infopages, and `apropos` all exist. Individual man pages may be bad, but the system as a whole is solid. It also isn't dependent on the shell. All these mechanisms are just normal programs that can be executed by any shell.
> a rising tide lifts all ships but bash is the mooring block.
What?
You do know it runs on Windows, Mac (amd64/arm64) and Linux(amd64/arm)? There is definitely integration with .net, which is available for the same platforms. The integration with .net is part of its power for me.
Verbosity can increase readability.
> Is it? Why? Man pages, infopages, and `apropos` all exist. Individual man pages may be bad, but the system as a whole is solid. It also isn't dependent on the shell. All these mechanisms are just normal programs that can be executed by any shell.
You will not loose those tools and their man pages when using PowerShell. He is referring to the documentation of all helper functions defined within PowerShell. When you create a helper function in Bash, how do you document it and what tool can you use to consult that documentation?
Bash does not have named parameters for its functions, let alone metadata on them…
"Runs somewhere" and "Is useful there" are two very different things.
> Verbosity can increase readability.
And usually it hinders readability. If anyone disagrees, he may explain how enterprise Java is more readable than Python, Go or Rust code. And yes, I do consider Rust more readable than Enterprise Java.
And that's when we talk about PROGRAMMING LANGUAGES. We are, however, talking about SHELL LANGUAGES. Other than most PLs, shells are in fact written more than they are read, so yes, "typeability" and terseness is a feature in shells, not a problem. And before anyone says "autocomplete": If a shell requires autocomplete to be somewhat useable, I will look for another shell.
> You will not loose those tools and their man pages when using PowerShell.
Did I say I will? That line was in reply to the statement that "the help system is categorically better", a statement I happen to disagree with.
> He is referring to the documentation of all helper functions defined within PowerShell.
And I am refering to the documentation that is defined within the shell environment on *NIX terminals.
> When you create a helper function in Bash, how do you document it and what tool can you use to consult that documentation?
Off the top of my head:
- I can embed a `-h --help` flag directly in the script
- I can write a manpage and use it via `man NAME`
- A manpage is also discoverable by the `apropos` program
- If it's a builtin I can use bashs builtin `help PATTERN`
- I can write an entry for the `info` program
So yeah, I'd say there are more than enough methods, all of which are well established in the shell ecosystem, and work seamlessly with it.> Bash does not have named parameters for its functions, let alone metadata on them…
Which would truly be a bummer if bash needed named parameters. Since it doesn't, I don't see why this would be an advantage. If I want named params for a shell script, I can write it in python.
> Bash does not have named parameters for its functions, let alone metadata on them…
Come to think of it, actually a bash function can indeed have named parameters. Because that's exactly what command line flags with values are :-)
# these invocations are equivalent
awesome_util --source www.example.com --ignore-headers --dest file
awesome_util --dest file --source www.example.com --ignore-headers
awesome_util --ignore-headers --dest file --source www.example.com
In this example, it doesn't matter in what order I put the values for source, dest or the boolean to ignore headers, as they are all named by the associated command line flag.Compare for example the following helper code used for git command completion inside Bash and inside PowerShell.
Bash: https://github.com/git/git/blob/master/contrib/completion/gi... PowerShell: https://github.com/dahlbyk/posh-git/blob/master/src/GitPromp...
I believe this is clean Bash code and clean PowerShell code, and a script with a certain complexity. The functions inside the Bash script are documented using comments, the ones inside the PowerShell script are documented using "structured comments" (similar to javadoc/xmldoc/...). The parameters of the functions inside the PowerShell script also contain metadata which is used to provide completion on the commandline and similar functionality as the command line flags you demonstrated.
I just learned about 'getopts' in Bash, which you can actually also use to implement parameters to a Bash function. So what you are showing on a script level, can also be applied for functions. Did not know about that.
Still, not saying PowerShell is better than Bash in a Linux context, but it seems a lot of Linux users have a gut reaction to right out reject PowerShell. I think it does have some advantages for certain use cases, like more complex scripts, a cross-platform context, ... and of course, for someone with a .NET background it's easier to program more complex things with it.
You literally cannot write a powershell function that doesn't support get-help <myfunc>. So that's already a win it's self documenting because of the type system. The better the developer uses the type system the better the generated help. Sticking to the standard format for help (which is generated for you again from tab-complete) enhances this help document further. Finally, adding a url(https://learn.microsoft.com/en-us/powershell/scripting/devel...) lets the builtin update-help download new help, independent of publishing a new cmdlet version. So authors can fix typos/wording or add translations or examples without having to issue a release.
I've been doing linux sysadmin at least a decade, literally never heard of apropos before. I disagree that leaving this up to the authors is beneficial. When I'm lost and confused consistency is key.
Because this it builtin by default, it's worth it for the authors to add.
A lot of odd pwsh syntax is precisely because it's a proper language in a shell format, and just by that nature there's some ugly stuff in there. < > is already used so -le -gt -lte -eq exists.
Because it's a typed structured language, you will never have it without tab-complete, it's just designed in. That's the answer to maintain readability and typeabillity they chose. Bash just didn't choose readability. they both have alias' for common things. You may disagree but I would say that's just like refusing to use dot-sourcing or import statements in any language. It's there to use.
Your final remark about python I feel just adds to my point of don't bother with bash. I'd almost insist a shell that does even less then pwsh/bash and forced you to use a proper language sooner would be better.
The thing about programming is you have to at least nod to grammar and syntax and your IDE will sort you out (if you bother with one).
The thing about submitting an article on HN or to the world in general is ... why not proof read the very first line.
I doubt that any en_xx would "come around" and would prefer to "come across". Now that I read that critique back, I worry myself!
Anyway: "I ♥ to /bin/bash and last week I came across the one bash book to rule them all."