Effective Shell
effective-shell.com
effective-shell.com
But then, nope:
> Windows is not anything like Linux under the hood. So to get a shell working, we have three options:
> Use a tool which provides common Linux tools which have been written to work with Windows
> Use a "virtual machine" running Linux
> Use the Windows Subsystem for Linux
What "common Linux tools which have been written to work with Windows" is referring to is installing Cygwin.
This a fairly hamfisted presentation of a subject matter that could be handled in a way that is simultaneously easier to grasp and factually correct.
First of all, your goal is to teach about a specific command interpreter language, you really want to clarify how there are multiple ones which have different syntax, and brush that whole topic aside as fast as possible.
> You can see what the version is of your shell by running:
> bash --version
Yikes. If we know we are running Bash, the way to know what version it is is:
echo $BASH_VERSION
and not to run another instance of Bash.Can this book teach something simple, like comments?
> The shell ignores any text which follows a # hash symbol.
Wrong:
$ echo 'all of # this is seen'
all of # this is seen
"this is seen" looks like an example of "any text" to me.A hash comment marker is ignored if it is not quoted and escaped so as to be part of a word. The hash is also part of certain bits of syntax:
$# (dollar hash) number of positional parameters
${variable#pat} expand the content of variable, chopping off
a leading portion which matches the pat pattern.
Example:
$ echo $TERM
xterm-256color
$ echo ${TERM#xte}
rm-256color(I personally wouldn't write a book about the shell. I would be too paralyzed by the thought that at any moment, Stéphane Chazelas might crack it open.)
https://blog.nullspace.io/batch.html
Powershell is a new arrival, limited outside of Windows. I admit that I don't know it.
The POSIX shell also has severe problems with ambiguity, and it is not an LR-parsed language:
https://archive.fosdem.org/2018/schedule/event/code_parsing_...
Use the right tool for the job, imperfect as they may be.
It is unfortunate that awk didn't grow and supplant the shell, as for many years the BWK "One True Awk" did use straightforward lex and yacc grammars.
It’s actually based on the DOS command shell [1], which in turn was modeled after CP/M [2].
"For example, on OS/2 and Windows, it can use real pipes in command pipelines, allowing both sides of the pipeline to run concurrently. As a result, it is possible to redirect the standard error stream. (COMMAND.COM uses temporary files, and runs the two sides serially, one after the other.)"
Obviously, this process and I/O management would require a massive rewrite, sufficient to make cmd.exe a new (but somewhat compatible) implementation. This was not possible in DOS or CP/M.
Delayed variable expansion, pushd/popd, file name completion, expression evaluation and improved control structures are all fundamental changes that are strongly influenced by the Berkeley C Shell written by Bill Joy. The wiki specifically mentions the C Shell.
The 8086(/8) binary for command.com is not found in modern windows (I think the "wow16" layer was removed from 64-bit windows); cmd.exe is a 32-bit binary running under wow32, which it must be to invoke these new features in system calls that could not exist in DOS.
The wiki says this about the relation between command.com and cmd.exe:
"cmd.exe is the counterpart of COMMAND.COM in DOS and Windows 9x systems, and analogous to the Unix shells used on Unix-like systems."
I think that very little source code from command.com ended up in cmd.exe.
It is compatible with, but distinct from what preceded it.
I disagree with all of them from an educational point of view.
Having said that, it helps to clarify whether the audience is technical or education oriented. The title implies a technical book, so I'm with you on the comments.
This author doesn't have a chance in a room full of newbies. You have to have your technical dope straight, and it's not enough.
I've linked to this post/comments on the repo (issue #210), they should all get addressed but it might be a while before the online version gets sorted, I'm closing out the final chapters online, once I've done this I'll likely go back to the beginning and rewrite/edit/put in a more consistent style (more code snippets, fewer screenshots etc).
explorer.exe uses the "ShellApi" to do some of its things, which applications can also use, like launching a file via its associated application (ShellExecute/ShellExecuteEx).
$ echo foo#bar
foo#barThanks to those who've commented with corrections/suggestions, I'll go through them try and get the content fixed up where possible. Will need to have a lie down and possibly an epidural before going through the comments again to pull out the changes needed.
I learned how to use a POSIX shell years before I learned how to program (outside of a shell, that is), and I've often wondered how to help people (particularly younger colleagues) who learned things the other way around.
My experience so far is that a lot of people get stuck in an "experience trough," for lack of a better phrase: they're comfortable navigating around the filesystem and running basic commands, but struggle with some of the more powerful building blocks that can make someone a real shell power user (`xargs`, nontrivial uses of `find`, here-strings, subshells and blocks, process substitution, etc.).
This is very useful for those who are stumped by a failing script.
"I am a strong believer that Bourne-derived languages are extremely bad, on the same order of badness as Perl, for programming, and consider programming sh for any purpose other than as a super-portable, lowest-common-denominator platform for build or bootstrap scripts and the like, as an extremely misguided endeavor. As such you won’t see me spending many words on extensions particular to ksh, Bash, or whatever other shells may be popular."
For me, `cat | grep/sort` is easier to remember as it follows some unixy philosophy on how to do things.
I wonder why that article author is so obsessed with putting down cat/pipe. Maybe in scripts where you process large files and sort/grep it is less ineffective. But when writing shell commands, I see this as an empty argument to retrain my "muscle memory" and learn "different syntax".
In fact, when writing powershell I do the same: `gc something | sls something`. But I know it is less effective, but I'm lazy to look up proper syntax: `sls ?? something` - But if I ever will need that in a script to process non trivial amount of files-lines - I'll look it up.
For me, it was a lot of scripting and then iterating on those scripts when I realized that they conceptually broke down in places (even if they never broke in practice). Things like spaces where you don't want them, needing to pass around data that might be too large for `argv` (because of stack limits), etc.
It's just a different mindset. Instead of a std library you have tons of prebuilt binaries ready to perform actions and talk to one another. And that is really, really, powerful once you learn what's all available and how to use/abuse it.
Software engineering in general is so different. Tons of mantras to follow, TDD, OOP, etc.
Each has its place, but generally if I can do it in a few lines of shell, why spend 20 minutes writing a hundred lines of something more pure? On the other hand, shells do not seem well suited for anything large and complex, admittedly. So watching people waste an hour writing something that could be a Bash one liner is about as painful as watching someone try to debug a 500 line bash script.
I am one of those... as soon as I don't know how to do something in the shell, though, I just fire up a REPL or a "scratch" in the IDE and write what I want in a "proper" language. Sorry, but shel scripting is not always the best way to go. I eventually did learn me some AWK and that was useful, but most of the time I don't use even that, it's just so much easier for a programmer to use a programming language to do stuff.
for item in some_list:
foo(item)
Of course, the above is a replacement for "xargs -n 1" only; but I argue that the batching functionality of xargs isn't really needed in programming languages.I’m not really sure it’s fair to assume that you can use advanced topics after reading any book aimed at beginners.
Also, no one is going to learn how to use any of your advanced topics unless they have a need. And people rarely have a need for those things.
That "experience trough" you describe I think exists because they don't actually understand the fundamentals, so any time they've attempted something new it's based on assumptions from a totally different paradigm, does something strange and unexpected, and reinforces sticking to the same safe and simple commands.
Google shell style guide [0] was also a good read. I thought that the "When to use Shell" section is a section that is good for any kind of guide, not just for bash / shell.
Also, maybe not so much a pitfall / bug, but something I had to deal with recently was that bash does not handle the EINTR when calling write() in the printf and echo builtins [1][2][3], etc.
[0] https://google.github.io/styleguide/shellguide.html#s1.2-whe...
If you are writing a script that is more than 100 lines long, or that uses non-straightforward control flow logic, you should rewrite it in a more structured language now. Bear in mind that scripts grow. Rewrite your script early to avoid a more time-consuming rewrite at a later date.
[1] https://unix.stackexchange.com/a/487260 handle the EINTR when calling write() in the printf and echo builtins.
[2] https://github.com/torvalds/linux/blob/ca1fdab7fd27eb069df13... Q: what's up with this '/bin/echo' ?
A: bash's builtin 'echo' command does not check calls to write() against
errors. If you use it in the cgroup file system, you won't be
able to tell whether a command succeeded or failed.
[3] https://lists.gnu.org/archive/html/bug-bash/2018-01/msg00031... write() not retried after EINTR in printf and echoIt's fascinating. I wonder if it will be worth it for the change of command-line editing habits. It certainly feels faster for most command-line edits.
No hard feelings, I see how you might have read that from my comment.
And neither bash nor sh are that great, so no reason to put down the idea that they shouldn't be the "default"
When called as /bin/sh or if the POSIXLY_CORRECT environment variable is set, it will act as a POSIX shell.
If not, it will behave very differently. The one major difference that I know is that aliases will be ignored in the execution of a script, so "alias p=printf" will fail (for example). This is not POSIX-compliant.
#!/bin/sh
alias p=printf
p ok> When we talk about "The Shell", we're normally referring to the simple, text-based interface which is used to control a computer or a program.
This is a bit nitpicky, but I don't like this definition. This is conflating a TUI, a shell, and a terminal.
"The Shell" usually refers to `bash`, `zsh`, `fish`, `powershell`, or `cmd.exe`. The interface is the terminal (emulator), because programs like to dump ANSI control codes and the terminal takes those control codes and turn them into human-readable output with colours and such.
> Windows is actually being updated at the time of writing to provide a Linux-like shell interface as part of the core operating system (this is known as the Windows Subsystem Linux
No, no, no. This is just wrong.
If this was WSL1, you would be at least partially correct, since it's a re-implementation of linux syscalls and runtime environment on Windows, kinda like reverse-wine.
But with WSL2, windows now ships the entire linux kernel and virtualises it. The objective is not to provide a linux-like shell interface (whatever that means), but to let people run linux binaries on windows in a linux environment.
Either way, the fact that `bash` (or any other shell) runs on WSL is a result of bringing along the rest of the linux runtime environment.
> install instructions
For the entire WSL section, I'm pretty sure that you can install wsl these days with just `wsl --install` on powershell. Maybe it only works on win11 or something, I'll have to look up the docs. Winget also has ubuntu2004 in the repos. But this is not a linux-like shell on windows, this is using linux, virtualised, on windows.
Downloading homebrew just to install bash is ... interesting. Catalina is 3 years old, and I don't see any bash4/5 specific features that you're using (I had to google bash release notes lol). `zsh` is probably preferable anyways imo.
Also as a sidenote, you can get pretty close to a linux-like environment by just installing busybox on windows. You'll have to be careful around things that powershell aliased away, but if you decide to just prefer busybox for everything then you're like 90% of the way there.
> wget
For some bizarre reason, macos doesn't ship with `wget` by default. Don't ask me why :/
> renaissance of the shell
In my personal experience, shell usage has gone down, not up. What used to be shell scripts are now getting more and more specialised: sysv services became systemd, the rise of devops meant giant piles of Dockerfiles and YAML, etc.
It's still a critical part of system administration and development, but its tentacles are slowly receding from poking into every corner of everything to slightly less pokes in everything.
Because curl is better?
Probably because of its licence: wget is GNU, curl MIT. Apple stopped updating bash, e.g., due to licence changes, and won’t, in general, ship GPL based tools.
Homebrew to the rescue.
I agree with you, but the "giant piles of Dockerfiles" are actually mostly shell commands anyway.