Ccatp_2023_02_18

An audio podcast where Bart Busschots is teaching the audience to program. Associated tutorial shownotes are available at https://pbs.bartificer.net.

2021, Allison Sheridan
Chit Chat Across the Pond
https://podfeet.com

Edit Transcript Remove Highlighting Add Audio File
Export... ?

Transcript


[0:00] Music.

[0:08] Well, it's that time of the week again. It's time for Chit Chat Across the Pond.
This is episode number 759 for February 18th, 2023. And I'm your host, Alison Sheridan.
This week, our guest is Bart Bouchats with Programming by Stealth, number 144.
Are we going to keep playing with shell scripts today, Bart?
We are. And I'm actually in the middle of rewriting the name of the show notes, just as we start to record, because we are talking about conditionals.

[0:31] I initially gave the episode a more conservative name, because I wasn't sure we'd get through it all in one install.
Installments, but we did. So we get to go all the way from last time we learned that the terminal does boolean-like things in a unique and interesting way.
These things called exit codes, where up is down and down is up.

[0:53] Or zero is true and anything else is false, which is pretty, it makes my head hurt still. But they are the basis for controller flow.

[1:04] So by controller flow, that's like a superset conditional statements which is do something on a certain condition or, unless a certain condition and the other obvious flow of control is looping. So, we're going to do half of that today but it's not really half because the first, thing we have to figure out is how to turn logical expressions into exit codes because exit codes are the key to everything so how do I turn some sort of concept like is this variable empty or does this variable equal that variable? I have to turn those kind of questions into exit codes because that's the only way we can do any sort of logic is with exit codes. So that's the first half of today's installment and it all revolves around what the bash documentation calls testing. And that's, there's a little bit of history. So I'm actually going to take you on a journey and we're going to arrive in a happy place and then once we arrive in that happy place you only have to do things the nice way but it is kind of useful to get there the hard way because otherwise it won't, make sense frankly unless you see how we got there it won't make sense.
And then we're ready to do the closest the terminal gets to an if statement but it's, not really a statement anyway it's interesting it's fun.

[2:23] So we will be able to do conditionals by the end of this installment that is what we are doing today. And that sets us up really well to do loops and arrays next time. Because, I'm slightly pleased you didn't notice me utterly utterly ignoring the existence of arrays as I talked about variables in the previous few weeks. I was rather hoping you wouldn't make me say, yeah, pause that for now because they're hard. But next time we'll get there. So.

[2:49] Wait wait remember just a quick reminder that we are writing in bash because it's a really good very well supported middle ground.
Bash is a second attempt at a Unix shell and the first one was called the born shell or just SH and then bash has actually been superseded now by ZSH the Z shell.
But bash is a really good baseline for really wide level support so that's the one we're using.
But way way back when SH was being invented in the 70s, the 1970s, the way you did test to get an exit code was with a command called test.
So there was an actual command for making these exit codes that you would use for all of your flow of control and the command was called test. And the command took either three or two arguments.
So if you remember way back to our early JavaScript stuff we talked about, most operators are binary operators because they take, like the plus is a binary operator, it's something, plus something, so that's binary.
But there's also unary operators. Exactly.
So there's also unary operators like plus plus, which just has a thing.
And the same is true for the test command.
So if you have a unary operator, it's test space the operator space the value to test. No, that's binary.

[4:19] That was two things. No. Test, the word test, test is the command, which takes two arguments.
The an operator and the value.
One operator, one value. You're saying it in the opposite order of the show notes.
I thought you said. I am. Yeah. Okay. So say it again so I don't interrupt you.
So if you're having one of the unary operators, it's the command test.
And then the first argument is an operator, which will start with a minus sign.
And the second argument is the value to test with that operator.
Okay. The other way is you have two values. So you have test. The first argument is the first value.
The second argument is the operator, which will start with a minus probably.
And the third argument is the second value.
So it's test value operator value or test operator value.

[5:03] There are the two modes of operation. And for backwards compatibility, yeah, for backwards compatibility, that still works.
Even in ZSH, that still works.
So if you'd like to play along, if you fire yourself up a terminal on your Mac, then you can use the test command to check to see whether or not you are currently in your home directory.
So test space and then the variable P WD in all caps contains the present working directories.
One of those magic environment variables we learned about in Taming the Terminal.
So if you do echo dollar P WD, you'll see it shows you your present working directory.
So we can test $pwd, so that'll be our first argument, and then we want to pass an operator as the second argument, and the operator we're going to use is the equals sign, which does not mean make equal to, it means is equal to, and that's going to make a lot of JavaScript programmers' heads explode.
But I'm afraid to say equals is equal to. And then we pass as a third argument tilde, which is the universal expansion, or the bash expansion for my home directory.
So we're saying is my present working directory the same as my home directory?
That's what that test does and then we're using a trick from last time where we use the and to say well if that's true also do this other thing echo your home.

[6:27] So if you do that with your home directory it should print your home and if you did that from any other directory it won't.
Yeah that works i was going to hear you say that when it's. Let's see, when it's got two arguments, two values, the operator sometimes has a minus sign in front of it.
So it's not minus equals, luckily. No, no. Because our heads get hurt even more.
Most of them are minus something.
Yes, a lot of them are minus a thing, but the equals is just an equals. Thank goodness.
So there's a few things to draw your attention to. So if you look in the show notes, you'll notice I had to quote the value $PWD inside double quotation marks.
And the reason for that is if the present working directory contains a space, then it would be seen as being multiple arguments because space is your delimiter for arguments.
So if you didn't quote that variable, then if you were say in your, let me see what one has a space, Mac doesn't call it my documents does it?

[7:35] There are folders on the Mac where there are spaces in them.
I know this because I've landed in some of them. Maybe that's my name. I make lots of them.
Yeah, maybe that's what maybe I do too. Maybe that's how that always happens to me.
I know if I was a good little Unix-y person I wouldn't do that but...
Oh no no, the Mac is Unix++. Spaces, yeah, I happily use them.
So that's why you have to quote, because it's just an argument, right?
It's a command with arguments.
The other thing is you absolutely, positively cannot cuddle your two values to your operator, because then it becomes one giant big argument, the string pwd equal to tilde, as the first argument, and then test goes, you've only given me one argument.
I literally have no idea what to do. That is not an operator, that is just what are you talking about?
So you have to space them out.
So they're the two things I want to draw your attention to. Another thing I want to draw your attention to is that because these are just arguments, to a command, if we try to compare something to the string star, we would have to be absolutely sure to quote the star, because otherwise bash would expand star into every file in the current bloody well directory.
And then you would have lots and lots and lots of arguments to your test command and it would get very very cranky indeed.
So these are just, it's a command with arguments so you have to do all of your escaping and you have to think about all of these possible things. Is there a space in there?
Am I using any special characters?
So it's a lot of faffing about.

[9:03] It's also, if you see a wall of code, like if you imagine just seeing a page of JavaScript code you'll figure out where the control of flow is quite quickly because the if statements will jump out at you. It's like two characters open a roundy bracket.
Like just the shape of your code would jump out at you.
Right. That is not true if you do test.

[9:27] Because there's no there's nothing to make it look any different.
So if you see a wall of code written this way, your conditions will not be obviously conditions.
It'll just look like a whole wall of text.
And so very early on, someone had the smart idea to simulate the shell, not bash, but this is the old shell, having some sort of a structure for conditionals.
They made an alias for the command test named open square bracket.
And they updated the test command to ignore a closed square bracket as a final argument.
So you can optionally pass a closed square bracket as an extra argument and it will ignore it.
So now you can write your test as open square bracket, your condition close square bracket.
And so now when you look at a wall of code the conditions jump out at you because they're, bracketed in these nice square brackets.

[10:20] It's a dirty dirty hack right? But if you look at the... actually I'm one step behind myself here so we have another example I should have done.
I skipped an example which is an important example.
So the present working directory example was an example of two values, right?
Where testing is one thing equal to another, that's two.
An example of a unary operator is the minus E which stands for exists.
Really useful. You give it any file path and if there's anything there, whether it be a folder or a file or anything at all, it will minus E to success.
So test space minus E a path will tell you whether or not there's something there.
Really useful. So our second example is test space minus E space tilde slash dot bash underscore history ampersand ampersand echo you have a bash history file.
So if you have a bash history file it'll tell you you do and if you don't it will be silent.

[11:23] I don't know if you do or don't have a bash history. I do have a bash history because you've used bash.
Now I'm wondering whether I have a zsh history file. I can't remember if it's called zsh underscore history if it has a different name.
It apparently is because I have one.
There you go then.
That answers that. So again nothing too earth-chattering. Minus e for minus exists. Nice and easy one.
And then you just give it the value that it should be testing.
But it's very hard to read. It's just a bunch of glop. It's exactly.
It really is a wall. You can't tell where pieces of it are.

[11:58] So even just a dirty hack of aliasing the command test to open square bracket and making it ignore close square brackets when we rewrite those two examples they genuinely are more readable.
Open square bracket dollar pwd equals tilde close square bracket ampersand ampersand echo your home that like breaks it up here's my condition and here's what I do.
The second example, open square bracket minus e tilde hit bash history, close square bracket.

[12:26] Ampersand ampersand echo, you have a bash history.
Again, you've broken up your what, what am I testing and what do I do into two really obvious separate pieces. So it actually does work.
But there's still lots of little gotchas here, right? So square bracket is a terminal command.
It's a weirdly named terminal command, but it is a terminal command.
So you cannot cuddle, because again, then you will be running the command open square bracket quote dollar pwd close quote, which is not a command that exists.
The fact that open square bracket is a command that exists is weird, but that would just be really weird.
I just tested it, there's a man page. If you type man space left square bracket, it tells you beast test.
You can.

[13:09] Yeah. So it's open square bracket space because it's command space and then it's arguments.
And then all of the caveats I gave you before still apply, you still have to worry about your stars and you still have to quote your variables because again if there's spaces in there it becomes multiple arguments so the command named open square bracket and you can't cuddle the closing square bracket for all the same reasons because it has to be an argument all by itself so it can't be cuddled.
But again less icky.
But thankfully we live in the world of bash and in the world of bash it was decided that one of the, problems to be solved when making the shell better was to have an actual native construct for doing tests. And so there's a key word instead of just the terminal command we use for doing tests in bash and they decided to double down on the convention literally.
So the bash and above, it also works in zsh, the bash and above keyword is open square bracket open square bracket.

[14:14] Wait, I didn't catch what problem we've solved by having two of them instead of one.
We are now not running a terminal command, we are now running a bash feature, a built-in functionality of bash.
OK, so this two square brackets would not work at the command line.
It works on the command line, but it's not a terminal command.
It is, in fact, something that tells the shell go into a different mode.
So it's syntax for the shell, not a terminal command.

[14:45] Tilde is syntax for the shell, right? It's it is it has it's not any old command sitting in your slash user slash bin folder.
Folder, it's actual keyword.
Like in JavaScript, if is a keyword. Right?
So it is a special incantation. It has special meaning.
There's no man page for square bracket square bracket.
So I'll remember it that way.
Because it's not a terminal command. Yeah. Because it's not a command.
It is actually a feature of the language.
So it's a fundamental part of the language. It's a language construct, a keyword.
And it puts the terminal into a different mode between the opening square brackets.
The opening pair of square brackets and the matching closing pair.
So between those two, the rules of the universe are different.

[15:30] Music.

[15:39] Which means that you are freed from having to quote variables.
Because you're not in terminal command with arguments, you are inside square brackets.
And so bash is like, don't waste your time quoting, I'll do the right thing.
Because we're now in a special little universe defined by those square brackets.
So no more quoting of variables. No more worrying about star expanding out into a bunch of file names.
File globbing is disabled.
So that expansion is called file globbing. File globbing is disabled inside square brackets.
But special characters like tilde still work.

[16:13] Because they don't multiply things. is a thing.
Star could become infinity things or no things tilde is a thing so tilde we get to keep, So no more quoting our variables, We still get to keep tilde, but we don't have to stress about our stars And so now you can rewrite the above again even simpler, So it's square bracket square bracket space still can't cuddle things square bracket square bracket space dollar PWD space equals space tilde space square bracket square bracket and then whatever we want to do.
So no quotes around the dollar pwb, pwd was the main thing to get from that.
But we still have to not cuddle anything anywhere within those double square brackets.
Yes, because again, you do still need to tell it a thing, an operator, a thing, or an operator, a thing.
So our minus e example is still as it was. So open square bracket, open square bracket space minus e space tilde bash history.
But again, we've now ended up with, because we live in Bash and ZSH world, we've ended up with a much nicer construct and the thing to say, you will find answers on Google that, use single square brackets.

[17:24] Do not use those. For you, I want everyone listening to this show to remember, for everything we do in this series, always, always, always, always use square brackets.
I very strongly advise you adopt the same for all of your scripting, because otherwise you'll go nuts because special characters will sometimes do weird and wonderful things and bite you in the backside because you were accidentally using single square brackets instead of double square brackets.
And it's one of those things where 90% of the time you'll get away with it until you accidentally use the wrong special character and then boom, it explodes.
Or worse still, you don't code a variable and 90% of the time there's no spaces in the value so your script works almost always apart from the second Tuesday of the month when it really explodes. And that's what causes these kind of weird inconsistencies. So always, always always use the double square brackets. We live in the future. Make the most of us.

[18:19] Okay, so I'm not going to list... I feel like I'm still going to quote my variables because I'm going to have trouble remembering that I don't need to inside square brackets, but would it hurt if you...
It won't do any harm. No, it won't do any harm whatsoever.
No harm whatsoever. It's just extra characters.
Okay, we have the disk space. What's two bytes? Really?
So, there are a lot of operators. So I have a link in the show notes to the bash documentation with the full list, but, I will highlight my favourites.
No, not my favourites, the one you're most likely to need. So the first set of operators that you probably are going to use more than any others are actually the unary operators that do file-like things.

[19:03] They are for interrogating file paths on your disk. And if you think about scripting you're always, you know, is the thing here?
Make it exist. Is the thing here? Throw an error. Can I write to this file?
Can I read this file? Those are the kind of questions you will have as a scripter.
So we've already seen minus E to check if something exists. Minus F is like minus E but stricter.
Not only is there something here, is it a file.
So if you do a minus F on your home directory you get back fail.
Because yes your home directory exists, but it's not a file.
Minus D checks for a directory, which is what Unix and Linux and the shell call folders to us modern people. So minus D for directory, minus R is is it readable? Minus W is is it writable? Minus X is is it executable? And minus S is is it not empty? Does it have a size greater than zero is why it got that name. So not only is there a file here to to use as input for my script.

[20:04] Does it have anything for my script to ingest? You may have some sort of process that expects something else to have spat something out.
Well, if the file exists isn't actually the right test, if you're going to ingest something, is there something for me to ingest is actually a more meaningful test.
So minus S is often the right thing to do to check, am I good to go?
Can you pile these together? Like, can you say minus RWXS to find out if it's readable, writable, executable and non-empty all in one go?
I'm not sure you'd have to test that out. If not, you can use the OR operator to stick between multiple tests.
Worst case scenario. But given they start with minuses, my guess would be that you can chain them together.
But I didn't, honestly didn't try.
Okay. I'm going to do something with your pronunciation of the letter R.
You said or like O R correct.

[21:02] As in you can put on so the or operator pipe pipe like we saw last week. Great.
You can stick between so you can have square bracket square bracket blah blah blah close your square brackets or so pipe pipe more square brackets.
Okay. Chain them together that way. Okay.

[21:20] So the next thing then is strings right so files are obviously a big thing for shell shell scripts, but strings are kind of bash and ZSH and all these things.
Strings are their first love, right? Numbers to them are actually just strings of characters, which is why they do very dumb things with numbers, which we'll get to in a moment.
So string operators are the most important as well.
There are two very useful unary operators. There's minus Z for is an empty string.
So if you want to test, is this empty?
Minus Z will tell you if it's empty. So if you have a variable or the output of a command, something you want to test is this empty?
Minus 8.

[22:03] Okay. If you want to test if it's not empty, it's minus N for not empty.
Yeah, there's only 26 letters in the alphabet. They had to get a bit creative and remember I'm leaving most of them out.

[22:16] We've already seen the equal sign to check for equality. Exclamation point equals is not equal.
So that's, that's, we'll feel at home there as JavaScripters.
The next two are going to make you cranky.
The less than sign does not mean a numeric comparison. and it means an alphabetical, a lexical comparison.
Does this sort alphabetically before the other?
Oh, that's handy. Which it is and it isn't, because if you if you do any of these operators, right, four is less than 10.
Because, sorry, four is not less than 10. Four less than 10 will return fail because one zero will sort ahead of four.

[22:59] Wait, isn't 10, doesn't it start with a T? And four starts with an F?
No, no, one zero. No, no, as in the digit four is not less than the digit one zero.
So you write four space. Oh, oh, oh, oh, you said you were doing strings.
So I thought you were doing strings. That's what I mean. That's what I mean.
So this operator looks like, like the minus sign looks like a mathematical operator.
In most languages it would be a mathematical operator. It is an alphabetic operator.
Right, right. I didn't know that you meant 1, 0, I thought you were meaning T, E, N.
No. Because you said strings. But you also said that it treats numbers as strings.
It does, yeah. Exactly. Which means it does dumb things. So 4 less than 10 is fail.
The other thing that fails is 0 equals 0.0. They're not the same.

[23:47] Because the equality is a string comparison. They're not the same string.
You and I know that 0.0 is zero, but the shell is like, nope, those strings are different.
One long, three long, not the same.

[24:00] So I'm still having trouble with this. If you have the number four.

[24:07] And the number one zero and you alphabetize them in a save for a directory name, doesn't the one zero go after the four?

[24:17] Only on the Mac, which does non-standard alphabetization. It does human friendly alphabetization everywhere else. It goes the other way. One of the best things about the Mac OS is that it alphabetizes wrong in all the right ways. I find it very pleasing. So if you want to tell bash to do actual mathematics, you have to use effectively named operators that are way harder to read.
SEQ for a numeric equality, minus NE for a numeric inequality, minus LT for a numeric less than, minus GT for a numeric greater than, minus LE for a numeric less than or equal to, and no prices for guessing, minus GE for a numeric greater than or equal to.
That is annoying that the ones that have to do with strings look like math symbols and, the ones that have to do with math are the text symbols.
That's great. And in most programming languages it's exactly the opposite way round.
It is a real common cause of bugs.
Because this is bash being very odd. So it's a very common form of a bug.
And then there's one last useful one that doesn't fit into any of those categories.
Minus V checks if a variable of the given name exists.
So minus V pancakes. Is there a variable named pancakes?
It's potentially useful. Okay.

[25:41] Okay, so I now want to, before we go into how we do our conditionals, I want to take a moment in time to just get you used to the idea that things are about to get weird.
You're about to go through the looking glass.

[25:54] Although given the previous few minutes of conversation, we kind of already feel that, right?
You're not, you don't need much convincing most probably.
So we've only seen one language in detail, which is JavaScript.
But if I show someone who knows JavaScript a bunch of C or C++ or Java or Perl or PHP.

[26:13] You wouldn't be able to write it from scratch because there's subtleties in the syntax.
But you could look at someone else's code and go, ah yeah, it loops over this and then it does that.
Like you get a gist of the code quite well because it looks quite similar and you have code blocks inside curly braces.
You feel at home. None of that applies to bash.
To any of the shells really. They are just utterly different ways of thinking.
So don't think blocks of code with keywords defining what they do.
It's commands and only commands. Commands commands commands commands.
Some of them are special commands like the square bracket square bracket is a special, command, but it's still it's a one line. It's still command something command something command something.
So there isn't an if statement.
There's a collection of commands which together give you the behavior of an if statement.
At least three commands are needed for an if statement.
The if command, the then command and the fee command, which is if backwards.
This is a pattern. Right? Because you don't have code blocks.
So how do you signal the end of if-ness?
The command that's the opposite of if.

[27:30] I've seen that in Apple script does that. There are other places have copied the idea.
Yeah. So if and fee are basically stirred.
Yeah. So if basically the if command tells the terminal to go into a new mode, and the fee command says I'm done being in this mode.
Now go back to normal. It makes me so happy to know what fee means.
It's just if backwards.

[27:56] So that's how we have to think about these things. So let's start with the equivalent of an if statement in JavaScript.
So in JavaScript it's just if, open roundy bracket, condition, close roundy bracket, open curly bracket, some stuff, close curly bracket, right? That is a unit.
The if statement takes that form.
Well, we're not working that way. So we have the if command starts the shell into a new behavior.
So the if command takes as its first argument something that is a command, something that it can execute in some way.
And if you give it any extra arguments, it will take those as arguments to whatever the first one is. So you know the way with sudo, it's a command that treats its first argument as another command and then all the other arguments as arguments to the command.

[28:47] Right?

[28:47] So you have sudo do something arguments. Well, it's if do something arguments, but in reality, they're all arguments being given to the if command.
Like they're all arguments being given to the pseudo command, but the pseudo command decides my first argument is really a command. My second argument is the first argument.
My third argument is the second argument.
It just shifts them all. Git is kind of like that too, right?
Well, no, because Git is a command and then I guess it takes an instruction to give.
Yeah, but it takes an instruction. But in this case, it's terminal command.
So the second argument, the first argument is a second terminal command that will be executed by the shell.

[29:24] Which can be and usually is square bracket square bracket. Right. The most common thing to want to do. But it could be anything.
Because all that matters is it makes an exit code and everything makes an exit code.
Right. So the if just says whatever you tell me to do, all I care about is the exit code.
Right. You could ask me to format drive C.
As long as it gives me an exit code I will quite happily accept that as a condition.
Right? It's just, I don't care what it is, as long as I get an exit code I am going to either do something or not do it.
Because I'm an if statement. That's my role in life. Right?
So you say if and then you give it some arguments and it will execute those arguments as a command and it will remember the exit code.
And the next command you give it is the command then. And the command then can take either for pure convenience it can also take another command as its arguments or it can take no arguments.

[30:23] Because you are now in alternate if universe and basically the then and everything that follows the then until you do something else is not really executed yet it's basically whether or not we execute it depends on, the exit code the if got. If the if got a success, everything after the then is executed.
And this keeps happening until one of two things happens. Either you meet the fee command that says we're done. Or you meet an else command, which obviously flips it into a different mode.

[30:58] Or you meet a command we'll talk about in a minute called elif. E-L-I-F.
So this doesn't sound any different the way you described it from normal if then else.

[31:09] Well except that if, right but the if statement is you have a code braces around things right?
It's if something, then.
It's just how it works.

[31:21] That's also how it works, because there's no concept of a code block.
No, but if A is greater than B, then do this, else do this other thing.
That's just the way you described it just now in these bash conditionals.
If A is greater than B returns an exit code of zero, then it would do the then part.
Right, but you actually have to give the command then to start into then mode, whereas that's not the...
You do in JavaScript too. You have to say if then else.
I don't see any difference. No then in JavaScript.
It's if open bracket, some condition closed bracket, open curly, closed curly.
It's actually, in terms of how the compiler works, the if is one statement which has parts which are a condition closed in.
And you know something, if it works for you, I'm not going to talk you out of it.
If it makes sense to you, I'm not going to talk you out of it.
You haven't done a course in compilers. brain hasn't been broken by studying how compilers work.
Yeah, why am I trying to convince you it's hard? No, it's fine, it's easy!
If you keep working I bet you can get there.

[32:28] No that's not, that's a terrible waste of time. So the then command puts you in this new mode where we keep executing these stuff based on whether or not the if statement, the if command got a success.
And then the easiest way to finish up is with a fee, which is just basically, if this, do that, end the story. But you can also end your then block with an else block, and of course no prizes for guessing that you then have as much code as you want, followed by the fee.
So you can if then fee, or if then else fee, but you always end up with a fee.
Can you if then else then else then else then?
No, you only get one. You only get one else. But what you can have is as many as you like, LFs.
Which is LF is effectively a shortcut for else if then sorry else if because you go. Else if. Okay.
So LF is else if because you still have to do with then. So you can say if then.

[33:30] LF then, LF then, and you're allowed to have one else at the very end.
Perfect.

[33:38] So you, yeah, and you always, always, always end up with a fee.
The phi is always sitting there at the end.
Just to tie it. That is always your closing curly bracket is your phi at the very end.
So it is actually quite sensible.

[33:52] So if we look at, we have some examples. This time they're actually available in the zip file because they're a bit longer.
So our first example is PBS 145A.
It's called simpleif.sh. And what we're going to do with this little shell script is we're going to...
Basically, we're going to greet the user, and we're going to expect them to put their name as the first argument.
But if they don't do that, instead of shouting at them, we're going to use the read command, and there's a typo in the show notes I'm now fixing, but the actual shell script in the folder is correct.
So we're going to use a read command to ask them their name if they haven't told us their name, and then we can greet the user.
So in code we have our usual shebang line at the top. And then we're going to just assume that the first argument was given to us.
So we're going to say name equals dollar one, not cuddle together.
Because we don't cuddle our assignment. And then we're going to use our if statement to test whether or not the name is empty.
So if space square bracket square bracket space minus z space dollar name space close square bracket close square bracket.

[35:03] So we're passing if the one argument which is our square bracket statement.
And then on the next line we say then read space minus b space what's your name?
Phi.
Okay, hold still. I finally caught up to you because I didn't know there was a zip file.
I've now opened it up and I'm now looking at the file. So minus z again was is it an empty string?
Yes.
So if minus the dollar name is an empty string.

[35:37] So they would have had to have given us the name for it to exist.
Correct. So we're saying, so basically the line above, we say name becomes equal to dollar one.
So in other words, if they pass us an argument, we'll take it as the name. Okay.
Then we're saying, do we have a name? Run. Hang on, hang on.
Let me catch up. So you would, someone would run this script with an argument of their name or not.
If they ran it with it, it's going to say, what's your name?
Because it's an empty dollar name is an empty string.
Okay. Correct. I'm now caught up.
And then we just echo, well, hello there, dollar name, smiley face.
So hang on, hang on, hang on cowboy.
So you've already feed us, we're done, but you can keep going after fee because the fee only ends finishes the if your script is still running.
I've just realized I've gotten away with something there that I think I'm very lucky because of how the shell is very forgiving.
That should be read minus p whatever into name, but it defaulted to going into the right variable because the shell does some really weird defaults.
That's bizarrely wonderful. I don't know what you've done wrong.
I don't know what it should say.
What should the script say?

[36:54] So between the then and the fee, we have our read command, which has a prompt telling us what text to put up, and then we are supposed to have the name of the variable to put the text into.
So as it should say after the closing quote it should be space name.

[37:13] But the shell does some very clever defaulting and it actually defaulted the shoving into the last variable it remembered being told about.
So it actually defaulted the shoving into name by spooky action at a distance, which, I strongly advise never relying on spooky action at a distance.
Okay, so let me try to say it from scratch now. So we're going to store the first argument as the name.
So name equals dollar one.
So if they executed the script space and a name, then when we test with our if statement, we say minus z dollar name, it checks to see if it's an empty string.
If it is an empty string, then read and minus p, and I don't remember what minus p is.
It's the prompt. So in other words, what do we put, what text do we tell the user before the pinky cursor?
So read a prompt that doesn't exist yet, but we're going to say dash P because we're going to tell it we're going to do a prompt.
What is your name space and whatever they get back from it, we should have put it into dollar name.
Into name. Ah, the name of the radio. Name, name, name, name.
Yeah, see. I did it. Fell right into the trap you said I would fall into every time.
Okay. Yep. Well, cause I do too. Okay.
And then, and then we fee, we stop our if, but the script is still running.
Fee isn't, we're all done.
It's just, it's not like a, an exit or anything. It's just saying we're done with the if statement.
And at that point, the next line executes, which is, echo, well, hello there,.ler name.

[38:42] Correct. So if you run that in your terminal with no arguments, then you will be prompted.
And if you run it with an argument, they will just print out the argument.
So you can see in the show notes the output from my terminal for running it both ways.
So I did it with an argument first.
And it just said, well, hello there, Bart. And then I did it without an argument.
And it said, what's your name?
I typed Bart. And then it said, well, hello there. Oh, it didn't say hello, Jebart, because of the typo in the script. Ha ha.
Ah, so it didn't spooky action at a distance. It wasn't spooky action at a distance.
I just looked at the...

[39:13] I just got a prompt and my brain was like, okay, that works.
Because the if statement was correct. So in his show notes right now, it says, well, hello there, blank smiley face.
Yeah. So I'll just fix it. I'm guessing you're fixing it too, which is fine because it will murder changes.
It'll be all good. Okay. Well, I'll fix it. Fix it.
Okay. I have fixed it. But that is that is good reminder. Okay.
That is very good reminder. So there we go. So that's a pretty good basic example, right?
It's not very exciting, but that is the simplest form of conditional.
Only do this thing if something is true. Or sorry, if something is success.

[39:47] The next most complicated type is basically your if-else. So our next example is number B, which we call PBS 145B if-else.sh. I'm very, very imaginative I am.
Can I interrupt you for just a minute to just make the audience a little bit crazier?
I just put it in with my name and it did echo it back.
It says, well, hello there, Alison. Before or after you fixed the typo.
I didn't fix the typo.

[40:16] Okay. So there was spooky at a distance. There is spooky action at a distance somewhere. Yeah.
The shell does a lot of defaulting, which can be really helpful or just mystery.
And I don't like mystery. So I tend to be a very explicit shell scripture.
Right. Right. Okay. So, so now we're looking at B. Let me open that one.
So example B is basically if some conditions should do one thing, otherwise do the other thing. So this is a very simple script. It's going to basically print out whether or not we have customised bash with a custom bash profile.
So we have our shebang line and then we say check whether or not the bash profile exists.
So we say if space square bracket square bracket space minus e space tilde slash dot bash underscore profile space close square brackets close square bracket. Then echo you've customised bash with the profile.
Else echo, you haven't customized bash, customized your bash profile yet.
Fee.

[41:14] So depending on whether or not you have a file called tilde, owners tilde dot bash underscore profile, you either will or won't. You'll see one of those two messages.

[41:24] In the earlier examples in your echo, and then you put a sentence in there, you like putting an exclamation point at the end so you've you've the backslash escaped it out, But when I run that command, it shows the escape character and the exclamation point.

[41:44] Why would that? Because exclamation points are an absolute bother to escape.

[41:54] Okay. I could probably, let me try, I could probably take it out and then stick a single quote, single quote, exclamation point on the very end.
Because remember, you can catenate strings by just shoving them next to each other.
So that would probably do it. So close, so after the E of profile, close the double quote, then immediately start a single quote, exclamation point, single quote. That should work.

[42:14] I think I would just not use exclamation points. That all sounds too hard.
But I like exclamation points. I do too. I do too.
I'm a big fan. But yeah, no, they are very troublesome in the terminal. Yeah.
Very troublesome. I struggle with them a lot. And it's a silly thing for me to spend time debugging, but I often do spend time debugging exclamation points. Okay. Well, by the time you see that, Burt will have fixed that as well.
Yes, he will. Because he just did. I'm getting better at this multitasking thing.
So the final example we have, and I'm very much doing this as a setup for where we're about to finish.
So the final example we have is our equivalent of else if, which is eleph.
And so our final, our second to final example is PBS 145 C called eleph.sh.
And again we have our shebang line and what this script is going to do is it's going to tell us the etymology of the current day of the week.
There are seven of those, so we have seven conditions to write.
So if you want to know how, you can look up the man page for the date command, but if you call the date command with a format string of plus percent a, it will give you the three-letter abbreviation of the current day of the week.
If you don't believe me, type date space, single quote plus percent a, single quote into the terminal, and it should say SAT.

[43:36] Unless you're Alistair right now at which point it's a different time of the year.
It's probably already sun, yeah.
Or yeah, probably. So anyway, we basically we execute that command and we shove the output into the variable name dow for day of the week.
Right, so that's the first thing we do there. So that's just going to be a three letter abbreviation.
So now we want to print the appropriate etymology, okay.
Why is Dow not have a dollar sign in front of it when you're defining it?
Because as we learned two weeks, two and so months ago, you don't give the dollar means, get me the value of. Okay. So when you're assigning a variable, you don't use a dollar, just like with the read command, you don't use a dollar. Yeah. Yeah. Okay. I got it backwards, again. Okay. Good. Oh yeah. I told you, you would.

[44:26] Shockingly, this may come up again. Okay. So we say no equals dollar and then this date plus, ampersand day or whatever is percent a that gives us the today's date. So Dow is always going to be the day of the week. Actually, dollar down is going to be the day of the week. Correct.
So now we basically start a whole bunch of statements. So if space opens square bracket, open square bracket space, dollar, Dow space equals space, the string moon.

[44:53] Which is basically going to test if the value of the variable DOW is the string Monday or SRA, the string M.O.N. then Echo Monday is named for the moon. Elif, square bracket square bracket space dollar Dow space equal space the string T.U.E. space close your square brackets then, Echo Tuesday is named for the Norse God Tyr. Elif space square bracket square bracket day of the week, Equals wed then echo elif right you get the way this works right so it's basically if then elif then elif then elif then until you get to the very end and you.
I'm from believe that you always have an a final trailing else and I do this in every language.
Which I often have very snotty messages in because in theory they should be impossible.
This is one of those things where you often see on the Shell script, impossible error.
It shouldn't be possible for this not to meet one of these criteria.
But anyway, my echo in this case is, what calendar are you on?
With three question marks.
I didn't know all those things. Thursday's name for the Norse god Thor.
Yeah. Wednesday is Odin.
I didn't know that. Yes, because Odin is Woden. Right. Woden is an alternative spelling of Odin.
So yeah. So Woden's day.
How did Saturday come from Freya?

[46:16] And that's Friday. Oops. Well, it says Saturday twice. Doggone it.
You can tell it isn't copying and pasting.
Okay. So who's Thor? Thor must be Thursday? Yeah.

[46:33] Thor's day is actually- Oh, I see. I see. I'm just reading it wrong.
Yeah, because it's this yes, if then and then you have it. So Thursday is actually Friday. Okay.

[46:45] Right. I'll fix this. Yeah. The copy paste, copy paste. I had a lot of copy paste.

[46:50] Right. So A, this shows you how LF works. B, this shows you why there is a second command for doing conditionals because it is actually quite normal to want to compare one value. So we were comparing DOW in each of those comparisons, right? DOW equal, DOW equal, DOW equal, every single time is DOW this.
It's really common in terminal commands to want to do that because you're often dealing with.

[47:15] What flag did they set or what option did they pass and you just have a bunch of possible values of the one variable. There is actually a command specifically for checking multiple values of one variable. So you basically say I want to check for this variable if it has this value do this, if it has this value do this, if it has this value do this, otherwise do that.
In JavaScript that is the switch command and so it's switch name of variable case case case case case. But on the shell the command is called case which again makes my head rather explode because that's not how normal programming languages work but hey that's there we go That's how these things go.
Right.
So... The case command is another example, like the two square brackets, of something that is new in Bash world.
And when you say case and then some stuff the terminal goes into a new mode. Like between case and it's...
You're immediately going to know why the last command is esac Case Backwards. Between Case and ESAC, the universe changes.
And there are special syntaxes that only exist between Case and ESAC.

[48:39] And so there's extra things your terminal can suddenly do between those two commands that it can't do anywhere else in your script.
So the way it works is you say case space and then you give it some sort of value.
Space the word in. And you have to say the word in. Right. It just has to be that way.
So case something in.
And that something could be a variable name. It could be command you execute.
Whatever it is. whatever it is that ends up as a first argument of case is what you're going to be checking all the way down.
So we're going to say case dollar DOW because we want to check DOW all the way down.
Okay. And what you then have is a collection of one or more pattern followed by the closing bracket, a whole bunch of code as much as we like, followed by two semicolons.
And then we repeat, repeat, repeat.
And the code between the pattern and the two semicolons only gets executed if the value of the thing at the top of the case statement matches the pattern.

[49:45] So this is harder to say than it is. I'm going to need an example of this part.
Oh, absolutely. We're rewriting our days of the week is what we're doing with all of the typos to fix again.
Okay.
So basically it's, once you say case, the next line must be a condition which ends in a closing round bracket. And if you want two conditions you can separate them with the pipe symbol.
And the pattern is in the same format as the grep command.
It's called bre, basic regular expression. But anything that works for grep will work here.
So A star means an A followed by any amount of anything. A?C would be an A followed by one other character followed by a C. That is how these patterns, work. Normally you just put a value here.
So the pattern is just a bloody string. 99.99% of the time. But you can use star and? and a few other things.
So let's just look at our...oh yeah, sorry, one final thing to say.
The equivalent of your final catch anything else is the pattern star, which means zero or more of anything.

[51:03] Okay. No idea what any of this looks like right now. This is just a bunch of semicolons and scroll down, scroll down. It's roundy.
The next example, PBS 145 D is the same code rewritten. So that way it makes a lot more sense because you do need to see this.
Okay. Let's yeah, let's walk through that because it's jumbly right now.
Yeah.

[51:22] So case space, something space in. So case dollar D O W space in.
In other words, everything between the case and the ESAC, the thing we are are checking the thing the patterns are matching is the $dow. Right? So the first pattern is mon and then we're ending the pattern with space close around bracket. So mon is the pattern. In other words is dow an m followed by an o followed by an n. If that is true we execute all the commands until the two semicolons which is just echo Monday is named for the moon.
Then we have our next pattern tue, end the pattern with a rounding bracket, some commands, Tuesday is named for the Norse God Tyr, two semicolons, next pattern, more commands, two semicolons, next pattern, more commands, two semicolons, next pattern, more commands, two semicolons.
The pattern is always being matched against $dow.
So if dow matches the pattern mon, run this code. If it matches the pattern tu, run this code.
If it matches the pattern wed, run this code. If it matches the pattern thr, run this code.
And then the last pattern is star.

[52:34] If anything else has happened, if we have anything else, if we're still going, echo, what color are you on?
Oh, OK. OK, so star is anything that hasn't already been described.
What if these patterns were mon space is space good?

[52:54] You wouldn't need quotes or? You shouldn't actually need to quote them because you're in regular expression land.
So as long as your pattern doesn't contain a roundy bracket, which you would have to escape, you're fine.
Because they're patterns. They're nuts.
Remember, we're in special, we're in, we're between the case and the ESAC, we're in weird universe.
Right. That is, that is a thing that Bash added to the shell that didn't used to exist in the old SH.
This idea that you can, that a command can take you into an alternate universe until you get to another command. So the case command puts us in an alternate universe until you meet ESAC.
So it leads to nicer codes. When you can see it, then it does in describing that was, that was a tough one to, to, Oh, you have no idea how hard those notes were to write.
So where are the exit codes involved in this part of the code?
Where are the exit codes happening?
So the case command doesn't really make use of exit codes because it's checking a value against patterns.

[53:59] It does with the if command turn. It does. Okay.
So the case command, not only it does, the case does return an exit code because everything returns an exit code. So the case commands exit code is one.
If none of the patterns matched and if you have a trailing star, that will never be true, but you don't have to have a trailing star. Right.
So if, if, if no code gets executed, it will return one, which is fail in all of the situations, the exit code of the last executed command will be the exit code of of ESAC.
Oh, okay. So if at the very end it just said, well, oh, you're saying the last thing before.
Hang on, hang on. Did you say the last thing before ESAC?
The last thing to be executed.
To be executed before ESAC. Yes. So, okay, imagine our star didn't say echo, what calendar are you on?
But said exit 404.

[54:55] Okay. If our week was, if our day was MON, the last command to execute would be echo Monday is the name of the moon, which would have an exit code of zero.
So our ESAC would have an exit code of zero.
If somehow our day of the week was none of those things and it got all the way to the star, then our exit code would be 404 from the exit 404.
Okay. Okay.

[55:20] Interesting. So, yeah. And again, the if statement, it's all about whatever the exit code is that the thing that comes after if determines whether you go to the then or the else or the LF etc.

[55:32] In fact the LF does a whole new exit code right because the LF checks to see well what What does this condition give me?

[55:39] So I wish we had Bart. I wish we had homework, even if it was something trivial to do.
I should have thought of that. Yeah. I'm out of practice because I really should have thought of that. You're dead right. I should have thought that, but I didn't.

[55:51] Because we've been going for quite a while learning new things where we haven't, had any sort of assignment.

[55:58] Yeah. I'm out of practice. I'm out of practice. That's sorry, Alison. That's my bad.
That's okay. Again, I'm the student in front of the class that everyone else hates.
Yeah, but I'm going to dream. I have two weeks to think of something because where we're going now is the next obvious step, which is, okay, great.
We can use our exit codes to control conditionals and we can use the case statement to simplify a lot of eliffs.
So the next obvious thing that you control with Booleans in any other language would be loops.
While something is true, do something, which in this case is while something is success, something because remember success is true. So that's where we're going next.
But of course what's the most likely thing to want to loop over?
It's an array. So let's learn about arrays in bash. That seems like a really sensible thing to pair next time.
So next time we're going to learn looping and arrays because they just go together like as the old song goes, like love and marriage. And then we are almost done of our tour of bash because the only thing left to do then is to deal with the pipe, to deal with the plumbing.
So our piping stuff to and from our shell scripts, which is very useful and very important, but we're not ready to do that until we've done all the other stuff.
So next time, loops and arrays, and then our final installment will be the plumbing, as I like to call it. So our pipes.

[57:17] All right. Well, this is fun, even though my head did hurt a little bit in the middle of it, I think we powered through and the show notes are perfect.
Well, except for all the typos. I was gonna say, what else do we need to fix still?
Are very helpful to getting this going. Well, we'll go over that after we're done recording here, Bart, but this is good.
This is fun. I like it.
Excellent. Excellent. Excellent. Well, folks, until we speak again, happy computing.

[57:44] If you learn as much from Bart each week as I do, I'd like you to go over to letstalk.ie, and press one of the buttons over there to help support him.
He does 98% of the work here. I'm just the stooge that listens to him and asks the dumb questions.
If you go over to letstashtalk.ie, you can support him on Patreon, you can donate via PayPal, or you can use one of his referral links.
I really hope you'll go over and help him out.
In the meantime, you can contact me at podfeed or check out all of the shows we do over there, over at podfeed.com. Thanks for listening and see you next time.

[58:20] Music.