 Well, it's that time of the week again. It's time for Chitchat 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 Boo Shots 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. No, it's just as we start to record, because we are talking about conditionals. I initially gave the episode a more conservative name, because I wasn't sure we'd get through it all in one installment, 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, 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. So by controller flow, that's like a superset of conditional statements, which is do something on a certain condition, or on less 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 thing that can spit out. 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 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 as a 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 interval it gets to an if statement. But it's not really a statement. Anyway, it's interesting. It's fun. 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 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. OK, so way, way, remember just, I guess, 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 a binary. That was two things. No, test, the word test, test of the command, which takes two arguments, the unoperator and the value. One operator, one value. You're saying it in the opposite order of the show notes. I am, yeah. OK, 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. 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. They're 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 PWD in all caps contains the present working directory. It's one of those magic environment variables we learned about in timing the terminal. So if you do echo $PWD, 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 us a third argument, tilde, which is the universal 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 our trick from last time where we use the and to say, well, if that's true, also do this other thing, echo your home. So if you do that way during 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 glad to hear you say that when it's, let's see, when it's got two arguments, two values. Two values. Sorry, two values. The operator sometimes has a minus sign in front of it. So it's not minus equals, luckily. No, no, most of them are minus something. Yes, a lot of them are minus a thing, but no, the equals is just an equals. Well, 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 dollar 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? Does Mac doesn't call it my documents, does it? There are folders on the Mac where there are spaces in them. I know this because I've landed in some of them. Or maybe that's one of them. Well, 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 Unixy person, I wouldn't do that, but... Oh, no, no, the Mac is Unix plus plus 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 wanna draw your attention to. Another thing I wanna 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 world 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. 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 a shape of your code will jump out at you. That is not true if you do test 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 conditioned. 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. And so now you can write your test as open square bracket, your condition closed 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. It's a dirty, dirty hack, right? But if you look at the, actually, so 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. I don't know if you do or don't have a bash history. Well, you probably 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 or if it has a different name. It apparently is, because I have one. There you go then, that answers that. So again, nothing too arch-addering, 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. So even just that dirty hack of aliasing the command test to open square bracket and making it ignore closed square brackets, when we rewrite those two examples, they genuinely are more readable. Open square bracket, dollar PWD equals tilde, closed 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, closed square bracket, 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. So you have to say- There's a man page. Man space left square bracket. It tells you- You can. 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 of 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. 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. Okay, 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. Tilda is syntax for the shell, right? It's not any old command sitting in your slash user slash bin 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. It is not a terminal command with argument. It is actually a bash test, 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. Because they don't multiply things, tilde 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 and 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 quote from dollar PWD was the main thing to get from that, 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. Okay. 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. 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 bracket instead of double square bracket. And it's one of those things where 90% of the time you'll get away with it till you accidentally use the wrong special character and then boom, it explodes. Or worse still, you don't quote a variable and 90% of the time there's no spaces in the value. So your script works almost always, part of the second Tuesday of the month when it weirdly 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 it. Okay, so I'm not gonna list. I'm feeling like I'm gonna still quote my variables because I'm gonna 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 the, my favorites. All right, no, not my favorites. The one you're most likely to need. So the first set of operators that you probably are gonna use more than any others are actually the unary operators that do file-like things. 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? You know, can I write to this file? Can I read this file? Those are the kind of questions you will have as a scripture. 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'll 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 use as input for my script, does it have anything for my script to ingest? Now 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 gonna do something with your pronunciation of the letter r, you said or, like or, correct? As in you can put on, so the or operator pipe pipe like we saw last week. Great, okay. You can stick between so you can have square brackets, square bracket, blah, blah, blah, blah, close your square brackets or, so pipe pipe, more square brackets, you can chain them together that way. Okay. So the next thing then is strings, right? So files are obviously a big thing for shell scripts but strings are kind of bash and ZSH and all these things are 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 wanna 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 wanna test is this empty, minus Z. Okay. If you wanna test if it's not empty, it's minus N for not empty. Yeah, there's only 26 errors in the alphabet. They had to get a bit creative. And remember, I'm leaving most of them out. We've already seen the equal sign to check for equality. Eximation point equals is not equal. So 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. It means an alphabetical, a lexical comparison. Does this sort alphabetically before the other? Oh, that's handy. Which it isn't, it isn't. Because 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. 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. 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. But I didn't know that you meant one zero. I thought you were meaning TEN. 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 four less than 10 is fail. The other thing that fails is zero equals 0.0. They're not the same. 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, no, those strings are different. One long, three long, not the same. So I'm still having trouble with this. If you have the number four and the number one zero, and you alphabetize them in a, say, for a directory name, doesn't the one zero go after the four? Only on the Mac, which does non-standard alphabetization. It's a 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. Minus EQ 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 prizes 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's also, it makes me, 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. 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. 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 Pearl or PHP, you wouldn't be able to write it from scratch because there's subtleties in the syntax, but you could look at some analysis code and go, ah, yeah, there's, you know, 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, right? 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. It's 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. Like 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 with a command that's the opposite of if? I've seen that in AppleScript does that. There are other places of copy the idea, yeah. So if and fee are basically stir, 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. Makes me so happy to know what fee means. It's just if backwards, yeah. 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, right? So if 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 sudo command, but the sudo 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 it, I guess it takes an instruction to git. Yeah, it takes an instruction. But in this case, it's terminal command, right? So the second argument, the first argument is a second terminal command that will be executed by the shell, 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? 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 have 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 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 or you meet a command, we'll talk about in a minute called elif ELIF. So this doesn't sound any different the way you described it from normal if then else. Well, except that if, right? But the if statement is you have a code braces around things, right? It's if something that's just how it then it's also how it works because there's no concept, right? There's no concept of a code block. 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 or that's not. You're doing JavaScript too. You have to say if then else. I don't see any difference. It's if open bracket, some condition close bracket, open curly, close 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 your brain hasn't been broken by giving you how compilers work. 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. 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 was 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 price is forgetting 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. Then our last. Can you if then, else then, else then, else then? No, what you can, you're going to 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. LF, okay. So LF is else if because you still have to do a then. So you can say if then, da da da da da, LF then, da da da da da, LF then, da da da da da. And you're allowed to have one else at the very end. Perfect. So you, yeah. And you always, always, always end up with a fee. The fee is always sitting there at the end just to tie it. That is always your like your closing curly bracket is your fee at the very end. So it is actually quite sensible. 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 PBS145A. It's called simple if.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 when 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 shoe bang 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. 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 c again was, is it an empty string? Yes. So if minus c dollar name is an empty string, so they would have had to have given us the name for it to exist. Correct. So we're saying, so 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? 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 without, it's going to say what's your name because it's an empty string. Dollar name is an empty string. Okay. Correct. So that's what we're going to do. And then we're going to say, well, hello there, dollar name, smiley face. So hang on, hang on, slow down, 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 shell script is still running. I've just realized I've gotten away with something there that I got 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 default. That's bizarrely wonderful that that actually worked. Okay, I don't know what you've done wrong. I don't know what it should say. What should the script say? 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 it should say after the closing quote, it should be space name. 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 gonna 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, let's see, 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 text do we tell the user before the pinky cursor? So read a prompt that doesn't exist yet, but we're gonna say dash P because we're gonna tell it, we're gonna 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 phrase. No, name, name, name, name, yes, they did it, fell right into the trap, you said I would fall into every time, okay. Yep, I'll excite you too. Okay, 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 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, dollar name. 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 I just said, well, hello there, Bart. And then I did it without an argument, and I said, what's your name? I typed Bart, and then I said, well, hello there. Oh, it didn't say hello there, Bart, 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, 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 Git will murder, changes it, it'll be all good. Okay, well, I'll 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 a success. The next most complicated type is basically your AFLs. So our next example is number B, which is called PBS145BFLs.sh. I'm very, very imaginative I am. Can I repeat 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, Allison. Before or after you fixed the typo. I didn't fix the typo. Okay, so in the waspukia, there is spooky action in the distance somewhere. 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 now we're looking at B. So example B is basically if some condition should do one thing, otherwise do the other thing. So this is a very simple script. It's gonna basically print out whether or not we have customized bash with a custom bash profile. So we have Russia bang 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 bracket, close square bracket. Then echo, you've customized bash with a profile. Else, echo, you haven't customized bash, or customized your bash profile yet, fee. So depending on whether or not you have a file called tilde dot bash underscore profile, you either will or won't. You'll see one of those two messages. 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, the backslash that you've escaped it out. But when I run that command, it shows the escape character and the exclamation point. Why would that? Because exclamation points are an absolute bother to escape. Okay. I could, 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 while 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. 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 I see that Bert will, Bert 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 LZ, which is LF. And so our final, our second from final example is PBS145C called LF.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. Unless you're Alistair right now, 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, D-O-W, for day of the week. All 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. You told me. Shockingly, this may come up again. Okay, so we say Dow equals dollar and then this date plus ampersand A 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 Dow 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, opens square bracket space, dollar Dow, space equals space, the string mun, which is basically going to test if the value of the variable Dow is the string mun day, or sorry, the string mun, then echo mun day is named for the mun. Elef, oh, space, square bracket, square bracket, space, dollar, dow, space equals space, the string, TUE, space, close your square brackets, then echo, choose day is named for the Norse God tier. Elef, space, square bracket, square bracket, day of the week equals wed, then echo, elef, right? You get the way this works, right? So it's basically if, then, elef, then, elef, then, elef, then until you get to the very end and I'm a firm believer that you always have a final trailing else. I'm going to 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, right? 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? Wednesday is Odin? I didn't know that. Yes, because Odin is Odin, right? Odin is an alternative spelling of Odin. So yeah, so Odin's day. How did Saturday come from Freya? And that's Friday. Oops, it says Saturday twice. Don't got it. You can tell I did some copying and pasting. Okay, so I'm fixing that too. Who's Thor? Thor must be Thursday? Yeah, Thor's day is actually. Oh, I see, I see. I'm just reading it wrong. Yeah, because it's, yeah, it says if, then, and then you have it. So Thursday is actually Friday. Okay. Right, I'll fix this figure. Yeah, the copy paste, copy paste. I'll take a lot of copy paste. Now, all 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 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 basically, 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. Okay. 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, 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. Oh, I like it. Between case and esac, the universe changes. And there are special syntaxes that only exist between case and esac. 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 I end, 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. So this is harder to say than it is. I'm going to give you 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 B or E, 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 question mark C will be an A followed by one other character followed by a C, right? That is how these patterns work. Normally you just put a value here. So the pattern is just a bloody straight, 99.99% of the time, but you can use star and question mark and a few other things. Okay. 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. Okay. No idea what any of this looks like right now. This is just a bunch of- Scroll down. Like semicolons and- Scroll down, scroll down. The next example, PBS145D is the same code rewritten. So that way it makes a lot more sense because you do need to see this. Okay. Yeah, let's walk through that because it's jumbly right now. Yeah. So case, space, something space in. So case, dollar, DOW, space in. In other words, everything between the case and the ESAC, the thing we are checking, the thing the patterns are matching is the dollar, DOW. Right. So the first pattern is M-O-N and then we're ending the pattern with space closed around bracket. So M-O-N is the pattern. In other words, is DOW and 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, T-U-E end the pattern with the rounding bracket, some commands, Tuesday is named for the North Scott tier, 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 dollar, DOW. So if DOW matches the pattern moon, run this code. If it matches the pattern T-U, 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. If anything else has happened, If we have anything else, if we're still going, Echo, what color are you on? Oh, okay. Okay, so star is anything that hasn't already been described. What if these patterns were mun space is space good? You wouldn't have been 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'd have to escape, you're fine. Because they're patterns, they're not, remember, we're in special, we're in, between the case and the ESAC, we're in weird universe. Right, that is a thing that Bash added to the shell that didn't used to exist in the old SH, this idea 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 we meet ESAC. So it leads to a nicer code. When you can see it, then it does in describing. That was a tough one to... Oh, you have no idea how hard those notes were to write. I bet. So where are the exit codes involved in this part of the code? Where are we having exit codes happening? So the case command doesn't really make use of exit codes because it's checking a value against patterns. With the if command. Okay, so the case command, the case does return an exit code because everything returns an exit code. So the case command's 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 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 ESAC. Oh, okay. So if at the very end, it just said, well... Oh, you're saying the last thing before... 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. Okay. If our week was, if our day was M-O-N, the last command to execute will 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, interesting. So, yeah. And again, the if statement, it's all about whatever the exit code is but the thing that comes after if, determines whether you go to the then, or the else, or the LF, et cetera. In fact, the LF does a whole new exit code, right? Because the LF checks to see, well, what does this condition give me? 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 of that, but I didn't. Because we've been going for quite a while, learning new things where we haven't had any sort of assignment. 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, right? Yeah, but I'm gonna 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 LFs. 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, do something, because remember which success is true. And 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 and bash. That seems like the really sensible thing to pair next time. So the next time we're gonna 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 strips, which is very useful and very important, but that is 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. 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 in 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. If you learn as much from Bart each week as I do, I'd like you to go over to lets-talk.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 lets-talk.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 Podfeet or check out all of the shows we do over there over at podfeet.com. Thanks for listening and stay subscribed.