Hacker News new | past | comments | ask | show | jobs | submit login
The bash book to rule them all (fabiensanglard.net)
240 points by tosh 11 months ago | hide | past | favorite | 128 comments



Dupe: https://news.ycombinator.com/item?id=38187450 (the url here has `index.html` at the end, so wasn't automatically caught as dupe)


I'm not sure the book is actually about bash specifically, but let's talk about shells anyway.

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.)


The solution you want is to target posix compatibility; you can choose how strict you want to be with that (ie essentially every posix compatible shell also supports the `local` keyword).


In order to be sure that your scripts work across most of the shells, you can also aim at POSIX compatibility.


I dutifully refer you to the ancient texts:

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...>


What's a good useful difference between .bashrc and .bashprofile? I usually just ignore everything but the rc files.


A shell can be interactive or non-interactive (eg. shell-scripts).

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`.


> An interactive shell can be a login-shell or a non-login-shell.

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


> Similarly doing ssh <host> <command> starts a non-interactive login shell.

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.


You can try this out:

  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.


> A shell run via `sshd` is technically not an interactive shell, as it is started by the ssh-daemon.

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`?


"Interactive" in this sense has less to do with how the shell is used, and more with how it is invoked and connected to it's environment.

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.


Huh. My intuition would have been that stdin/stderr provided by sshd to the shell would have been been marked as `isatty(3)`. TIL.


The interesting thing is, `isatty()` seems to report 1 even over an ssh connection...so yeah, purely from that point of view, the shell should be "interactive". Why this case is then marked as special in the bash manpage, I cannot say :D


This diagram should clear things up in a confusing manner.

https://i.pinimg.com/736x/13/be/5b/13be5b89e662930a2b2dc1573...


I would expect nothing less from Bash. Presumably this is the simplified version...


> You want a pretty book with a beautiful Saker falcon illustration on the cover?

I don't really get where the trend of making software books with animals on the cover originates from, but the parodies are fantastic.

https://boyter.org/2016/04/collection-orly-book-covers/


https://en.wikipedia.org/wiki/O%27Reilly_Media#Early_days

> The original cover art consisted of animal designs developed by Edie Freedman because she thought that Unix program names sounded like "weird animals".[2]


The reason is provided in the last pages of many books that they are either endangered or important/keystone species who are threatened.


And if the cover animal is in colour there’s colour inside, if it’s got a black and white animal then there’s only black and white print inside


Not true. Author of colored cover with bw book...


Interesting… they obviously changed there approach in the last few years


I think it's just cheaper to use public domain illustrations than to hire an artist.


Thanks for this, made my evening!


I love this article. Short and to the point. I'll go get this book.


I do not agree with an approach of a book that starts with bash.

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.


I answered every one of those questions “yes, but why is this even a thing?” Only in shell can something as simple as global variables be a “fallacy”.


Just so everyone's aware: the author receives a commission for each book sold through their Amazon link, so take that into account when reading their review.


Is there a (legal) way to get this book in pdf?



I find it interesting that the e-book costs over 4x the paperback from Amazon, which I just ordered.


Thanks. Strangely I'd never heard of this site before.


The wooledge bashguide:1: and bashfaq:2: are the best bash resources I’ve ever read.

:1: https://mywiki.wooledge.org/FullBashGuide

:2: https://mywiki.wooledge.org/BashFAQ


Don't forget to read up on the pitfalls too: https://mywiki.wooledge.org/BashPitfalls

However, I would put using ShellCheck as the single most important way to improve your shell scripts


Thanks for the recommendation. In my case, GPT revolutionized the way I use bash. If you know what you want to accomplish, gone are the days of endlessly fiddling around with syntax.


There's a method that's even faster than asking ChatGPT what to type, and that's knowing what to type.

For tasks you do regularly, it's worth the investment to learn.


True, but we cannot possible learn all the things. I wrote a nice little batch script last week with the help of ChatGPT. This is something I have to do maybe once or twice a year and I am sure someone who does this every day was a lot faster, but what took me maybe 30 mins would've taken me a day.


I agree. Here it's being used like a translation app: convert English into the shell language. That's all well and good for a place you're going to visit a couple of times, but if you plan on living there, you need to learn the local language.


Being able to use a tool akin to Google translate is a fantastic boon to language learning though.


Absolutely! It’s a fantastic learning cool, but not a substitute for actual learning.


Yes.

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.


You really should compare your typing speed with chatgpt if you think you can out type it for a question that you know.

Once I write the document string of the function I want it gets it right faster than anyone I know.


I like this method. The problem with it is that there's just too much stuff to know. So let me teach you another method. Don't try to know everything, learn to get things from other resources, one of which is chatGPT. Worth the investment to be wise about what you pick and choose to learn.


Until the day when GPT hallucinates some nice (and confident) rm -rf equivalent for you ;)


For me bash is a weird exception to the rule "code is easier to write than it is read". I'm never doing anything crazy in a shell a script but it's easy to just ask ChatGPT to whip it up for me and I will read it to verify. Perhaps anybody who can't validate the output is just as likely to write an accidentally-destructive script the old fashioned way.


Which is extremely easy to do; just a misplaced `mv` is enough. I can't believe people are relying on GPT for ad hoc destructive I/O.


Have you actually tried it? Because this comment seems pretty misplaced with the reality of what ChatGPT can accomplish. I also use it all the time for bash one-liners, and so far my experience has been "80% work correctly on the first try, 15% require minor adjustment to run, 5% require major adjustment to run" and so far none have ever done anything flagrantly wrong or destructive. It also doesn't just print a command with no context: it explains what each flag/step of the command is purportedly doing, which you can (and should!) use to double-check that what you're about to run makes sense. Which is more than I can say for a lot of SO answers!


Traditionally, the alternative wasn't "SO answers", which are indeed dangerous in their own way -- it was to develop, and then maintain, a comprehensive and fluent understanding of the tools suitable to your profession.

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.


A master carpenter that only uses hand tools is a master of their craft, and should be respected as such, but refusing to ever use power tools because of a moral objection to electricity would be seen as quite the eccentricity. Which, the Amish sell furniture, and it's really quite good, if niche, furniture.


I'd rather get to AI-assisted mastery of many more different crafts than limit myself to achieving mastery of just one single thing.


I've used chatGPT(ver 4 through ChATGPT plus) for creating .bat files. Really easy ones, it can churn out quite well. A lil more complicated - it doesn't consider edge cases. Several cases require me to ask it to generate a golang program that gets called by the .bat file.

Several times, I had to spend hours to get a .bat script working. Hopefully, it will get better in the future.


I used chat gpt to explain what a complex line in a bash script was doing. Though to be fair if I'd spent a day in man pages and Google I'd probably have learned a lot more than just being given the answer. Which makes think in the long run gpt may result in worse programmers.


In the same way as Stack Overflow has resulted in worse programmers, at least in some senses.

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.


And a generation before that, it was VB and (early) PHP programmers that earned that critique.

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 one of my BIGGEST frustrations learning to program. i do...not...want....to go online to work out hooow to do something. I want a "manual" - written well...that i can study and find the write tools to use...which for example (Pythons docs...are not...at least for beginners) - i then want to use the tools in said manual....to create. With the syntax, and the words you've defined oh so well in said manual. But...as the language grows...we'll just have to live with this never happening :)

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.


Books are still written, and there are quite a few online courses, and some of them aren't bad. I've learned that to be productive in a new language or framework I really need to dive into some of those resources. The manuals you find online are rarely good enough to learn from, and all the tutorials and "getting started" just scratches enough on the surface to make me frustrated.


Programs were smaller with less expectations on them. Users were few and forcily clustered near the computer system. Attackers were limited and computer security was physical access control security.

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.


I’d say that we are programming on a higher level of abstraction today, so the programs do in some senses do more, but the size of the code we wrote then and now, and the complexities are of the same order of magnitude.


What's better: spending a day figuring out a single line of a complex Bash script, or spending that same day learning literally 100x more because you didn't have to waste that much effort on each individual thing?

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.


Losing interest and not figuring it out at all has been my approach to nontrivial bash. I'm not a UNIX philosophy fan in general, but trying to bea programming language and also a UI, all in one, is a bit much. It's ok-ish as a UI for cases where GUI doesn't work or you want a machine to be able to use the UI, but as a language it's missing a lot of stuff.


Other option: asking the grey beard down the hall how to do it. Fifteen minutes, and all parties are happy.


https://explainshell.com/ can help with that but isn't perfect.


Bash doesn’t deserve the brainspace that truly knowing it would demand.


There's a big difference between "build this program for me" and "explain how this line of bash code works".

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.


Both could be equally wrong and hallucinated.


> Both could be equally wrong and hallucinated.

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.


This statement implies that LLM hallucinations are completely random which is objectively false.

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.


Why the downvotes? The comment is not rude and it is factually correct.


Not my downvotes but this is factually incorrect.

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.


Now that is of course going to be extremely unlikely in your example.

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!


That’s like saying a roll of dice is deterministic. In theory and under controlled circumstances, yes. In the real world and how people use it, no. The OpenAI docs even mention this, it’s only about consistency.

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.


Again, you've missed my point entirely. The reason for mentioning determinism was that I am telling you that the burden of proof for "DROP table1;" must be on someone who makes a claim such as yours, not me, and that such proof better come with some evidence, hence:

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.


So what? Review and test it before running in production. Humans also screw things up on first attempts. Test it, check the output, fix it, try again. In my experience with GPT-4 if you describe a bug it will correct it.


I haven't tried GPT for this purpose but I don't think we need to assume that everyone tinkering with it are blindly copy pasting potentially destructive commands.

Anyone who does that now would already have done it from random Google results anyway.


It’s really useful for learning. “Describe this complex bash command I found on stack overflow line-by-line”. Write a quiz question to make sure I understand it. Rate my response to this quiz question.


> Write a quiz question to make sure I understand it. Rate my response to this quiz question.

I like this idea. Definitely gonna steal it.

I love that "extensions" can be implemented just by writing a couple extra words.


This is what I come to HN for. I'll see if ChatGPT could maybe generate some relevant Anki cards as well.


>Which is extremely easy to do; just a misplaced `mv` is enough.

Or `chown -r` or was it.. `chown -R`


It shouldn't be too difficult to pipe chatgpt output to bard or something equivalent and ask for validation


You can also (surprisingly) ask ChatGPT for validation. The part of the LLM that activates when solving problems is going to be different than the one that activates when reviewing.


Not used GPT much?


Just last week I was asked to provide some possible screening questions to recruit for a Devops role. I figured this would be good:

"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.


That's an unwise way to filter out candidates. It's an obscure and unimportant syntax feature whose effect can be accomplished in many other, more readable ways. Writing line noise using obscure syntax is not a sign of a good programmer. If you want to find good candidates, give them an assignment in bash and make them explain their solution.


I am very proficient in Bash. My day job is as a Senior DevOps engineer. If I were doing an interview and was asked that question, I would never give the answer `${1:?}` (if I even remember at the time that it existed) because it is terrible code. It is obscure and unreadable.

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.


Is this for an in-person interview?

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.


I said "Give me the most succinct possible idiom" and it gave me the answer you were looking for: https://chat.openai.com/share/05a3d1aa-cd60-40a1-b6d5-ec0c9f...


The first answer is wrong, so is the second's explanation... twice it conflates unset with null/empty. Very illustrative!

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`)


Thanks for the tip, I now know that I can’t use ChatGPT when I’m being interviewed with this question.


Good luck with that, hope you never have to write a portable shell script


I mean, the man page is the Bash book to rule them all, but it's not a fun or light read. If you want to truly understand Bash you need to read it.


For a more organized read from the authors at GNU, try the online version of > info bash

https://www.gnu.org/software/bash/manual/bash.html


I've used bash for the last 10 years but never read the man page, probably never even opened it once. Is there some nugget of knowledge that I've missed out on by learning it entirely from Google searches and Stack Exchange?


`man bash` is, hands down and by far, the most accurate and complete bash resource.

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.


Yeah, I've been deep in the bash manual and source code during my work on https://www.oilshell.org, which basically reimplements a "cleaned up" spec-driven bash (called OSH).

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.


Usually when I can't find a simple way to do something, only a messy/complicated one, I find it worth popping into the info file and looking around - as long as you're comfortable using bash-specific (vs POSIX) idioms, there's often some generalization that helps. (Having said that, stack overflow "isn't great until it is", I've found some real gems of "can't you just do this?" that vastly simplify what I was trying to do by, effectively, doing something else entirely.)

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...)


There's a reason the man page is 200 pages long with 43,000 words. There's a lot more there than you imagine, much of it subtle.

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.


Wait. Why are you reading the bash man page without fully understanding man?

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?


While man pages may not be for reading end to end, Bash's man pages are actually Info documents i.e. They're books with clear chapters, and are intended to be read like books.


Actually, if you truly, really want to understand Bash by my personal arbitrary standard, then you must be able to produce the entire source code from memory, because that is the real book to rule them all. Sure, you might be able to navigate your everyday tasks perfectly, but that's not what matters now is it?


I feel anyone that really likes bash needs to have a concerted effort to learn how powershell works. It's got a lot of failings and MS has made deploying things and using them a pain but there's some genius in there and specifically the help system is categorically better. nushell is having a similar crack at it.

a rising tide lifts all ships but bash is the mooring block.


No this doesn't really make sense. Unix shell is "situated in" a bunch of native executables (grep, awk, ripgrep, etc.) and textual data, while PowerShell is VM-based, with bindings to Windows.

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.


Believe GP meant it as (not necessarily end up using it due to lacking the environment as you said) "check pwsh to see how things can be if you think bash is good". Worth noting, since you mention that pwsh has bindings only to Windows, that it's possible to make Linux-specific cmdlets/bindings in fashion similar to your YSH if understood it correctly (that is layering an object environment atop the text i/o of Linux commands).


In PowerShell, you can skip the need to master numerous DSLs for various data formats. Simply convert XML, JSON, YAML, etc., into objects and leverage built-in methods for manipulation. Bash, on the other hand, often requires you to familiarize yourself with tools like xmlstarlet and JQ, making the learning curve steeper. Additionally, PowerShell offers enhanced reliability since it primarily deals with structured data rather than raw text. Its consistency is also a notable advantage when compared to Bash, and the longer cmdlet names are offset by handy 2-3 letter abbreviations.


I'd like to add my issue with the specific DSL approach isn't the learning curve, but the curve is a saw tooth pattern. If you don't keep using those DSL's weekly, in 2 years I dare you to write a valid one from memory.

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.


Sorry, but powershell is not going to help me manage a bunch of linux machines and it doesn't come with all the usual gnu tools that I'm used to. I keep thinking that I should do more complicated stuff in a proper language, but BASH is just positioned as a perfect duck-tape kind of language - it ties together a bunch of other tools and I know it's going to already be there on any Linux machine that I deal with.


Duct tape. Ducks are glueless.


You might be surprised (as I was), when you consult Wikipedia on this topic: https://en.m.wikipedia.org/wiki/Duck_tape


My whole life, I've been lied to. Thank you.


I gave powershell a good try but I believe it sucks. too verbose and the syntax is too inconsistent.

trying nushell next, it looks very promising.


There are short aliases for the most used Cmdlets and tab completion takes care of the rest. Type "Get-Process -" and then press CTRL-Space for a list of all arguments. That works with any Cmdlet. Impossible in bash. PowerShell is one of the best ideas to ever come out of Microsoft.


so one of the best ideas to ever come out of microsoft is an attempt to copy the functionality of bash and incorporate it into their .net ecosystem? i hardly think this is a compliment


> why invent PowerShell, why not just use ksh or bash? I’m a long time Unix dev so that was my first instinct. I tried and failed. There is a core architectural difference between Unix and Windows. Linux is a file-oriented OS and Windows is an API-oriented OS. In Linux, if you can modify a file and run a process, you can manage anything. That is why awk, sed, and grep are management tools. At the time, nothing on Windows worked that way. Everything was behind an API which returned a structured object. That is why awk doesn’t work with WMI, sed doesn’t work with Active Directory, and grep doesn’t work against the registry. I had to invent a new tool that manipulated this environment.

- Jeffrey Snover, Powershell Inventor.

https://evrone.com/blog/jeffrey-snover-interview

Literally designed not to copy bash.


It’s not like bash (or UNIX shells in general) have invented command line interfaces…


I do not understand the "inconsistent" comment either. The "verbose" comment I can follow, but since you have tab-completion, it does not really matter that much.

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.


The POSIX shell, like the 1988 version of the Korn shell before it, is able to operate with minimal memory.

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.


Some (topical) amusements:

    $ 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 ...


I really like bash. I tried to like powershell. Nushell feels much better than powershell to me as it's not overspecialized for integration with .Net and it gets many of the shell niceties right out of the box (vi mode, simultaneous history and file autocomplete).

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.


I feel like anyone disagreeing with me that they won't swap to powershell every day from now on didn't really read my point and just clutched bash harder. I just said learn from it a bit, you don't have to live with it. It's not perfect, it won't replace your unix tools and bash because it never promised to, it's different. Python isn't trying really hard to be a better javascript.


Powershell for Linux fails the Litmus test of "Is it in the Debian community repo"

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.


https://github.com/PowerShell/PowerShell/blob/master/LICENSE... is the MIT license. (Microsoft supplies debs directly which may reduce the motivation for Debian to do so.)

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.)


> needs to have a concerted effort to learn how powershell works.

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?


> 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.

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…


> You do know it runs on Windows, Mac (amd64/arm64) and Linux(amd64/arm)?

"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.


So to defend the help points because it's interesting;

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.


Oh, and just another observation about this point right here:

> 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.


Yes, but you are referring to standalone scripts, not functions defined within a Bash script.

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.


"I ♥ to /bin/bash and last week I came around the one bash book to rule them all."

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."


English is not his native language




Consider applying for YC's W25 batch! Applications are open till Nov 12.

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

Search: