Making Hard Things Easy
jvns.ca
jvns.ca
Tools that do this make things clearer almost immediately. Consider the developer tools in a web browser. Do you remember the "dark ages" before such things existed? It was awful because you had to guess instead of seeing what was going on.
Tools like Wireshark that show you every last byte of network packets that it has access to AND parses it to help you see the structure. This isn't just for debugging networking data; it's hugely beneficial in teaching networking concepts because nothing is hidden.
This is also one of my favorite things about open source software. I can view the source to understand what's causing a bug, to fill in knowledge gaps left by the documentation, or just learn more about programming concepts. Nothing is hidden.
So yes it comes close but it just goes to show you, there is always more detail hiding somewhere!
In the article, it was pointed out that DNS caches can be hidden. They're especially hidden when they're upstream and in another computer!
This can be used to detect partially-bad network cables, because there is no reason you should ever receive a bad FCS.
ethhdr only has 14 bytes: 6 for dest mac address, 6 for source mac address, 2 for ethertype (e.g. IPv4 vs IPv6).
Any bad checksums that Wireshark can detect are predominantly at the transport layer (L4; TCP / UDP).
You'd have to explicitly turn on FCS, which I don't know if you can even do on, say, Windows.
See eg this bit about wlan for some of the complexity: https://wiki.wireshark.org/CaptureSetup/WLAN#link-layer-radi...
You set an environment variable to instruct the app the write a file that Wireshark can use to decrypt its traffic, and change a setting in Wireshark to use that file, and that's it.
You will even be able to see decrypted WebRTC traffic.
(Or back in the day, looking at the source code because we ran uncompiled stuff in Basic and whatever and that was pretty cool)
It's also awesome to use Java IDEs that can show both the bytecode of .class files and also perform decompilation.
We are visualizing things in our head already. And any explanation of anything in computing is a diagram. But we have zero diagrams when coding.
Just dynamically instrument all code to send messages to a GUI.
It's one of the areas that homoiconicity helps: code is data, data is code, so visualization tools can work on both sides.
Check out demos of the old Lisp Machines, [1] is a brief overview demo, [2] links to a timestamp with a view of some simple diagramming, but I’ve seen TI-Symbolics beasts routinely display complex relationships in Lisp code on their massive (for the time) bitmapped screens. The limitation was the end user managing the visualization complexity.
With open source llvm, clang and similar making available abstract syntax trees and even semantic analysis and type checking results, LLM’s assisting with decompiling binary blobs, and modern hardware (goggles, graphics cards, and so on), I sometimes wonder how close we can come to reproducing that aspect of the Lisp Machine experience on open source operating systems.
On the contrary, you don't need the source, and in some cases it may even be misleading in many ways, when you can look directly at the instructions the machine executes. Tools like disassemblers and decompilers would be equivalent to what you speak of.
At least with all the DevOps shit going on now, it seems that many of the tools increasingly hide things. And the gurus who had that knowledge and could teach you are now concentrated in those tool companies instead of in your org.
The proc filesystem on Linux is philosophically similar. It allows you to understand processes by working with files.
Is there a way to get Awk to emit a non-terse version of the script passed in? ie awk '/test/' -> '{ if($0~/test/){print $0} }'
It’s really easy to bleed one into the other.
> But I would say this is factually untrue. How many of you are using bash?
I think the meaning of the statement is not that straightforwardly literal.
I think what it means is, "We don't have strong confidence in our understanding of our bash code or confidence that it will behave as we expect in untested scenarios. If anything out of the ordinary happens, we kind of expect that something will fail and we will learn something new about bash that will make us cringe and/or strike a nearby object hard enough to injure ourselves."
Bash is a complex language, and for most programmers, it is unlike any other language they use. Most companies have a little bit in production somewhere, and most of them don't have a single person who writes enough bash to know it well. I think it's no accident that build tools, CI tools, and cloud orchestration tools are evolving in the direction of minimizing the need for shell scripting.
As a thought experiment, why couldn't bash have a better assignment statement available?
In other words, something like:
set --goodass
a = string1 + '.' + string2
This would cut through SO much of the shell quoting nonsense that you deal with.
another tool like "make" would benefit too.
I think 6 months of development to "make" to have usable variables, clear ways of manipulating paths and filenames and making targets more usable... that would be better than 6 months of creating complex makefiles.
Companies want developers to all know the same tools; that way they are easily replaceable across projects and companies and have little bargaining power in the industry. This is why software has a single mainstream trunk and alternative approaches are shunned with no jobs available. The industry is not being allowed to decentralize despite the fact that it naturally 'wants' to.
On the bright side, I think that eventually, some new, far superior non-mainstream approaches are going to materialize and they will erode the mainstream approaches.
Tech is not like math and not even like science; it can support MANY different branches solving any given problem in many different ways.
Stuff like DNS, IP, https can’t be helped as they are fundamental things that need backwards compatibility and are somewhat political too.
I feel that learning those things well is a better investment though than learning the frameworks.
… if I keep going I will start talking about innovation tokens!
The problem is that people don't necessarily bother to form a cognitive compression of a large topic until they really have to. That's because they already carry other large cognitive burdens with them, so they (we!) tend to resist adding new ones. If you can rely on someone else knowing some topic X well, you might just do that and not bother getting to know topic X well-enough. For those who know topic X well the best way to reduce help demand is to help others understand a minimal amount of topic X.
> So, bash is a programming language, right? But it's one of the weirdest programming languages that I work with.
Yes, `set -e` is broken. The need to quote everything (default splitting on $IFS) is broken. Globbing should be something one has to explicitly ask for -- sure, on the command-line that would be annoying, but in scripts it's a different story, and then you have to disable globbing globally, and globbing where you want to gets hard. Lots of bad defaults like that.
It's not just Bash, but also Ksh, and really, all the shells with the Bourne shell in their cultural or actual lineage.
As for SQL, yes, lots of people want the order of clauses to be redone. There's no reason it couldn't be -- I think it'd be a relatively small change to existing SQL parsers to allow clauses to come in different orders. But I don't have this particular cognitive problem, and I think it's because I know to look at the table sources first, but I'm not sure.
But I SSH into a lot of embedded systems these days, where you don't exactly have the luxury of installing your own shell all the time. For those times I like to whip out the "minimal safe Bash template" and `sftp` it to the server.
Also, we have ChatGPT now. That helps a lot.
My super power is a terrible memory. So I have to understand things in order to remember them (aka a cognitive compression). I can't just learn things like normal people.
The need to quote everything (default splitting on $IFS) is broken
Globbing should be something one has to explicitly ask for
By the way OSH runs existing shell scripts and ALSO fixes those 3 pitfalls, and more. Just add
shopt --set ysh:upgrade
to the top of your script, and those 3 things will go away.If anyone wants to help the project, download a tarball, test our claims, and write a blog post about it :)
Details:
https://www.oilshell.org/release/latest/doc/error-handling.h...
https://www.oilshell.org/release/latest/doc/simple-word-eval...
These docs are comprehensive, but most people don't want that level of detail, so having someone else test it and write something short would help!
For awhile I didn't "push" Oils because it still had a Python dependency. But it's now in pure C++, and good news: as of this week, we're beating bash on some compute-bound benchmarks!
(I/O bound scripts have always been the same speed, which is most shell scripts)
(Also, we still need to rename Oil -> YSH in those docs, that will probably cause some confusion for awhile - https://www.oilshell.org/blog/2023/03/rename.html )
https://lobste.rs/s/6gycoi/making_hard_things_easy#c_sjfxif
Feedback is welcome (especially based on upgrading real scripts)
We should peel off SQL and get access to the underlying layers.
Reference: https://www.gnu.org/software/bash/manual/bash.html#index-set
[ -e README ] && cat README
avoids an error if the file README doesn't exist, and [ -e README ] || echo "You should write a README!"
works the opposite way.What's more pernicious is that pipelines don't cause the shell to exit (assuming set -e) unless the last command fails:
grep foo README | sort
does not fail if README doesn't exist, unless you've also used `set -o pipefail`.The only thing /bin/false does is return 1. Is that a failure? No, that's how it was designed to work and literally what it is for. I have written hundreds of shell scripts and lots of them contain commands which quite normally return non-zero in order to do their job of checking a string for a certain pattern or whatever.
Programs are free to return whatever exit codes they want in any circumstance they want, and common convention is to return 0 upon success and non-zero upon failure. But the only thing that the shell is concerned with is that 0 evaluates to "true" and non-zero evaluates to "false" in the language.
It would be pretty inconvenient if the shell exited any time any program returned non-zero, otherwise if statements and loops would be impossible.
If a script should care about the return code of a particular program it runs, then it should check explicitly and do something about it. As you linked to, there are options you can set to make the shell exit if any command within it returns non-zero, and lots of beginner to intermediate shell script writers will _dogmatically_ insist that they be used for every script. But I have found these to be somewhat hacky and full of weird hard-to-handle edge cases in non-trivial scripts. My opinion is that if you find yourself needing those options in every script you write, maybe you should be writing Makefiles instead.
In another life I worked as a Jenkins basher and if I remember correctly I had this problem all the time with some Groovy dsl aborting on any non zero shell command exit. It was so annoying.
Some time ago I gave an example: https://news.ycombinator.com/item?id=22213830
A query's logic is declarative which defines the output. It's the query plan that has any sense of execution order or procedural nature to it. That's the first thing to learn. Then one can learn the fuzzy areas like dependent subqueries etc. But being able to see the equivalence between not-exists and an anti-join enables understanding and reasoning.
Using an analogy such as procedurally understanding of written queries only kicks the can further down the road, then when you're really stuck on something more complicated have no way to unravel the white lies.
She talked about a mental model to help her understand the query (it can be useful), and mentioned that it probably is not how the database actually processes the query.
An example of where muddling these ends up with real questions like "how does the db know what the select terms are when those sources aren't even defined yet?" By 'yet' they mean lexically but also procedurally.
1. The explanatory diagrams that Julia drew for the talk. These wouldn't make sense if they were in a different order.
2. The order of operations you would perform if you developed a proof of concept SQL implementation that completely ignored performance. In this example the order would be: "cats, filter, group, filter, map, sort". This is exactly the order that Julia's explanation showed.
3. The relational logic expression for this query. There should be a correspondence between this expression and this ordered list of operations, though it's somewhat annoying to state. I think it's that, assuming all the operators in the relational logic expression are binary, if you reverse the order that a subset of the operators are written in, then the operators in the tree occur in the same order as the ordered list of operations. (I don't actually know relational logic, so I'm making a prediction here. This prediction is falsifiable: you can't put the operators in the tree in an arbitrary order.)
(Side note: the order isn't completely fixed. The last two steps --- SELECT and ORDER BY --- could happen in either order.)
The best I can think of is Atuin (https://github.com/atuinsh/atuin) but I wasn't super interested in using it - I kind of want something more lightweight.
https://github.com/mikemccracken/hs
your snippets are stored in a git repo that you can sync around how you like.
For cases where you need to modify your current environment (setting environment variables, changing directories, etc), you need to run the script using the "source" built-in. That will execute the script in the current shell rather than a sub-shell.
So instead of
./some-script.sh
you'd run source some-script.sh
or use the dot (".") shorthand . some-script.sh
In cases where I need to source a script, I generally create an alias or a shell function for it. Otherwise I may forget to source it.It’s more like “roll your own oh-my-zsh”
I have a lot of aliases, for example to start my QEMU VM with my development stuff in it, I make an alias for 'qemu-system-x86_64 [...]' with all the switches and devices and files required, called 'startvm'. I have another that takes me to my current project's folder and pulls the repo. And a third that creates a new folder called 'newproject', creates a small set of folders and empty files with specific names, and finally makes a git repo in it. I am a serial abandoner of projects so I use this more often than I care to admit.
It's not pretty, but functional; and since I always copy my dotfiles when I change computers, I've kept these small helpers with me for a while now.
I've been thinking about updating the GIFs in my fzf tutorial to show off fish, but I think I'd rather leave them with ish just so I don't dilute the pedagogical message.
Just today I saved a new one for trimming borders on video screenshots https://xenodium.com/trimming-video-screenshots to https://github.com/xenodium/dwim-shell-command/blob/main/dwi... (that’s my cheat sheet).
I wrote an Emacs package that works fairly well for saving commands but also making them reusable from its file manager without the need to tweak input or output file paths https://github.com/xenodium/dwim-shell-command
While Emacs isn’t everyone’s cup of tea, I think the same concept can be applied elsewhere. Right click on file(s) from macOS Finder or Windows Explorer and apply any of those saved commands.
Edit: More examples…
- Stitching multiple images: https://xenodium.com/joining-images-from-the-comfort-of-dire...
- Batch apply on file selections: https://xenodium.com/emacs-dwim-shell-command
The man pages are readily available.
The bash man page is huge and hairy, but comprehensive, I've found it pretty valuable to be familiar with the major sections and the visual shape of the text in the man page so I can page through it quickly to locate the exact info I need. This is often faster than using a Internet search engine.
True, but I find the man pages not easy and quick to parse.
Use `/` and search for the things of interest (keywords, arguments, options, etc...). Use n/N to quickly jump forward/back.
But yeah, you're right.
However, I already have this in my muscle memory: find <where> -name '<what>' -type f(file)/d(directory)
Works in 90% of situations when searching for some file in terminal, ie: find / -name 'stuff*'
The rest of the time is spent figuring out exec/xargs. :)
And once you master that, swap xargs for GNU parallel. I bet your machine has a ton of cores, don't let then sit idly. ;)
man <command> | col -b | grep "search_string"
I recently found https://tldr.sh/ and found it more convenient. I ended up writing myself a vscode extension to have a quick lookup at my fingertips, since I am at least 60% of the time looking at a terminal in vscode
gm () { man $1 | col -b | grep --color=always "$2" }
I also have something similar for grepping a command's help
gh () { $1 --help | grep --color=always $2 }
I usually try gh(grep help) and if I don't get what I'm looking for, I run gm(grep man).
It appears that I can also use tldr
It was in fact on jvns.ca's book recommendation that I got Michael W. Lucas's _Networking for System Administrators_, and strip mined it for Anki cards containing both technical know-how and more than a little sysadmin wisdom.
It might be one of the highest ROI books I've ever read, considering I actually remember how to use things like nectat and tcpdump to debug transport layer issues at a moment's notice now.
Bash is terrible.
> ls -al
<repl>.ts:4:1 - error TS2304: Cannot find name 'ls'.
4 ls -al
~~
<repl>.ts:4:5 - error TS2304: Cannot find name 'al'.
4 ls -al
~~ $`ls -al`
or ls('al')
And, transpile shortcut strings on-the-fly to TS code: ls({
all: true,
oneEntryPerLine: true,
})The selective vision thing is so true, both for `dig` and for `man` pages. I can't count the number of times have I `man <cmd>` and just felt overwhelmed by the seemingly endless pages of configuration options and command line flags. One tip I use for `man` is use vim style search functions triggered with `/`. For example, if I want to find how to output the line number of each match in grep and I can't remember how - I'll just `man grep` then type `/line` and hit enter and it will search for any occurrence of the word "line" in the man page. Next match is just `/<enter>`.
I'm also a bit sad to hear that Strange Loop is now finished? I only found them last year or so and it seemed like so many of the talks were exceptional quality.
You might want to watch Alex Miller's talk that has been uploaded recently:
https://www.youtube.com/watch?v=suv76aL0NrA
And yes, it's sad that it ended!
However he made a very good case for why sometimes it's good for things to end. If you watch the whole talk it all makes sense.
Also I made https://github.com/kristopolous/mansnip
It lets you check the most commonly used options from your terminal, for example "tldr badblocks".
You can also press `n`
not to say we can't and shouldn't try to do better.
The problem is with bash itself.
We tend to undervalue ease of use and overvalue "cleverness."
Case in point: git. Very clever tool. Ease of use: terrible. But Linus wrote it and Linus is clever, so it must be us that's the problem.
We get what we value. Let's value ease of use more.
Actually what language does crash when a function returns false? I mean some throw exceptions but isn't "false" a valid thing to return?
I find the same thing with makefiles - people don't understand what they're doing and expect them to work in a certain way because they haven't ever thought about build systems very deeply. Recursive assignment in Make catches almost everyone out e.g.
FLAGS=-b
COMPILE=compile $(FLAGS)
$(info compile command=$(COMPILE))
FLAGS=-a
myfile:
echo $(COMPILE) $? -o $@
outputs:
t43562@rhodes:~ make -f t.mk
compile command=compile -b
echo compile -a -o myfile
compile -a -o myfile
Despite this, making all assignments immediate to match other programming languages would take a VERY useful tool away. The more you understand these tools the more you know where to bother using them and how much effort to put into it.
Many bad designs are too entrenched to be fixed with some tooling
Bash scripts are extremely useful and productive for their niche. You'd have to change a whole lot of things to match that.
That's not a very practical hill to die on. But well, you get to decide what fight you engage on.
The two most common alternatives are 1) using some of the newer shells people have created, like Oil shell [0], or 2) using programming language like Python, JavaScript, or PHP.
The problem with using a newer shell is that you'll have to install the new shell anywhere you want to use the script. Meanwhile bash is ubiquitous. Unless you're the only one maintaining the script, you're requiring others to learn the other shell to maintain the script.
The problem with using another programming language is that they rarely have good ergonomics for doing what bash does: stringing together commands, command input, command output, and files. If you try to do that in another programming language, things suddenly get a lot more complicate or at least more verbose.
So I still use bash, but I recognize that it's strength is in running other commands and dealing with I/O. If I'm doing complicated logic that doesn't involve that, then I'll offload my work to another language. Sometimes that just means calling a python script from bash, not avoiding bash completely.
If people found that they work better by taking other approaches, the please share them.
I've done this with awk and jq, but haven't done it with node or python. But why not? It sounds like a good approach for some cases.
tclsh is one way around that. Use a real first-class programming language, but in a mode where calling programs is as easy as it is in shell.
Best solution is to just stay away.
For real. Just stop. Don’t try to be macho. The whole model of the language is fundamentally broken. I mean, stringly typed, global mode switches, one-character flags for fundamental comparison operators, defaulting to ignoring errors at every corner you look, functions especially. Each such idiosyncrasy on its own is enough to dismiss such a language, bash has them all plus more.
And not to nitpick, but I don't have Julia's email, but when struggling with hard things like DNS I hate to have someone bounce off this little roadblock...her link to to the demo of the DNS exploration website is pointing to the .com, when it's actually at the .net TLD:
<a href="https://messwithdns.com">messwithdns.net</a>
^^^ =/= ^^^
Looks like someone needs an HTML linter... :)The correct link - https://messwithdns.net/ - is actually pretty neat!
fsf: which ps options should we use(bsd, systemv, solaris, sgi)?
also fsf: well that's a tricky one... why not all of them?
The linux ps man page is a wild mess.
It's really unfortunate that this will be the last one.
These are not hard, but I won’t remember ffmpeg flags because I only use it once per year.
So true!
been using SQL for years and didn't stop to think about that...
The reasonable approach is to start from high-level concepts and only then deal with the details - without specifying high-level concepts the details have no particular meaning.
As a side note I have to say that I definitely prefer languages with `object.function` rather than `function(object)`, precisely because of this. Another example: `if(foo == 5)`, not `if(5 == foo)`
I agree with having helpers to understand how tooling works. Any resources that increase understanding of how to use a tool to it's full capability is productively beneficial. (Hat-tip to anything that unpacks all the `curl` switches.)
Here's where I have disagreement: an old boss of mine once said "don't worry about the tricks of the trade; learn the trade." That's very contextual, but sometimes understanding the core first makes the rest of it easy. And understanding the core takes both effort and increases cognitive load, so I understand why one might not go that route.
So, for me, I always try to keep a balance between trying to back my way into execution via those helpers, and recognizing when I need to take a step back and learn at a bit more core level.
Her down-to-earth approach is refreshing, that's for sure.
Seems like you might agree more than you realize! From TFA:
> And much like when debugging a computer program, when you have a bug, you want to understand why the bug is happening if you're gonna fix it.
It sounds a lot like "don't worry about how to fix the bug; learn what the bug is."
I also never worked with vue before. At one point I found myself utterly confused; opening up a file to do something, and instantly forgetting what I was doing, having to go back and re-read code. I was super tired after an near all-nighter at this point, but felt like I had sleep deprived induced dementia or something. In occasional brief moments, I was totally unable to focus or remember what I was doing. Very interesting feeling actually.
When you have not worked with something before, and you are on a deadline, it is just a pretty awful experience. Vue, however, is supposed to be simple and make things easier for the developer. Well, not if you come from a back-end PHP background, with only moderate JavaScript experience, and there is literally no documentation on how things work in the CMS I am currently working with. Have to read existing code and try to replicate things. It is nasty beyond nasty!
Don't understand the script, but this is only for personal use. I wouldn't do the same in a work setting (obviously).
And in this specific example, it's been quite a powerful tool to make many parts of my life easier.
No, it's a shell that lets you interact with the OS. All the "clasical" UNIX shells were created with interactive use in mind and optimized for it, but happen to be good enough at batch processing[1] to be conflated with programming languages (mostly these days, like, 40+ years later).
The focus on interactive use is the reason you don't have to
- surround command argument lists with parentheses
- put commas between command arguments
- put semicolons at EOL
- surround string literals with quotes (unless the content interferes with the syntax, like, sigils or IFS chars, and you want to escape it).
- surround variable names in braces (unless you want to use some advanced substitution)
- call commands to manipulate I/O; it's baked in.
And these are just the things that existed 40 years ago. Bash gives you so much more stuff that makes interactive use a bliss, but I'm not going to dump the man page here.
If you optimize a shell feature for general-purpose programming, interactivity will suffer (increased verboseness, usually), and vice versa.
If we try to bring shells closer to the real PLs, instead of just using those PLs when it matters, we'll lose some of things that made shells attractive in the first place.
i like the way she broke it down. i feel like the author addressed ways to learn and communicate effectively and also grounded it in very concrete terms. i don't want to get too much into psychology or anything which i really am not qualified to talk about but i feel like going through these types of ways of learning and communicating is a continued exercise in ego deflation and in pragmatic problem solving.
i liked the SQL order-of-query-operations thing, the bash and shellcheck thoughts (i will use `-o all` from now on), i am curious to play with the DNS tool (the article links to https://messwithdns.com/ but the actual URL - taken from the text - is https://messwithdns.net/ , FYI), and i enjoyed the part about HTTP (i was hoping she would talk about SPDY and whatnot, i have not even begun to explore such things and am curious what that is all about).
i am going to read the two posts linked the behind-the-scenes on "hello, world".
thanks for the link!
edit: two things this made me think of:
1. the XKCD comic "ten thousand": https://xkcd.com/1053/
2. Mark Russinovich on git: https://twitter.com/markrussinovich/status/15784512452490526...
Are these hard problems? Maybe. Some HTTP problems are hard, and some are not. Some SQL problems are hard, and some are not.
Are tools intrinsically difficult? That's an even more complicated question because it is completely context dependent. A better question might be, does this particular tool make it harder to solve this particular problem than it otherwise might be?
And that's where you run into trouble. These tools have been designed to do a LOT -- to solve many different problems, both easy and hard. If you just "show everything", you may make the easy problem much harder to solve.
At the end of the day, some tools make some things easy (or possible!) to do in a way that they otherwise wouldn't. And we should appreciate that. There will always be hard problems, and for the most common ones, there are probably some better tools waiting to be written.
The essence of the software literacy revolution
"Share Tools we use to reduce cognitive load"
The essence of the FOSS revolution
Just one line and it was like a road to damascus
Julia is right: computers are great at remembering trivia. One of the best demonstrations of this, is compilers: they take in a high-level abstract program, and use a vast repertoire of knowledge about instruction sets, to transform the high-level abstract description of a program, into a program executable on a machine that’s much more awful to program for directly, with many more gotchas.
(Here’s where you say “Hey, wait a minute.”)
Why are we writing bash, when we could be writing programs in a higher-level language that compiles to bash? One with exceptions, at the very least.
(Yes, such a language would need a runtime that wraps every common binary and lifts its stdout + stderr + exit code -based semantics into safe, high level semantics. So what? That’s only 10000 “FFI bindings” or so for anything a normal person or sysadmin would want to call. For everything else, just ensure that writing your own FFI binding, inline to a script, is easy.)
If more people realized how great the chat AIs are for this purpose, they would be even more popular despite the hallucinations.
But as someone who rarely writes bash scripts but just enough to be dangerous ... I use `set -xe` at the top of every single shell script I write. The -x flag causes the script to echo every command that is executed to stdout which can be very valuable if I am debugging a shell script that is running on an external environment (like a CI). I've seen this habit suggested many times and it has served me well.
I'd have to look up exactly what's what, but if you're inclined to `-e` you probably want the others too. (Off the top of my head I think E is the same thing in functions, u is bail out if a variable is used without being defined (instead of treating it as empty string), and pipefail is similar for when you pipe to something else like `this_errs | grep something`.)
I don't like `-x` personally, I find it way too verbose; more confusing than helpful.
My suggestion would be to run your script like this `bash -x your_script.sh` when (and only when) you need to debug something.
I've not written a bash script in years. I always use Python and in my experience professionally, most people automating things nowaday use Python. I only use bash to write one-line to invoke the underlying Python script. For the record, I do the same for batch file on Windows, with a simply .bat file to invoke the underlying Python script.
Trying to improve the bash experience with tools and knowledge is throwing bad time at a problem that has a well-known solution.
Edit: to be clear, the presentation itself is awesome. I'm just disagreeing that bash needs to be better explained. I'm ready to admit that there are existing scripts out there, most of which are probably only working in the trivial, normal case and are just one snag away from exploding, and having a known source of help can help. But please, take you're bash scrip to the shed and upgrade them to Python.
https://news.ycombinator.com/item?id=37798978
https://news.ycombinator.com/item?id=37701022
https://news.ycombinator.com/item?id=37501934
https://news.ycombinator.com/item?id=37475760
https://news.ycombinator.com/item?id=37466497
https://news.ycombinator.com/item?id=37270270
https://news.ycombinator.com/item?id=37247594