Transcript
[0:00] Music.
[0:07] Well, it's that time of the week again. It's time for Chit Chat Across the Pond. This is episode number 761 for March 4th, 2023. And I'm your host, Alison Sheridan. This week, our guest is Bart Bouchats with another installment of Programming by Stealth. How are you doing today, Bart?
I am doing good. I've ended up with different show notes than I had planned to have and slightly different than what I promised, but I really like them. Does that make it better?
That's good. Yeah. Yeah. Well, we don't know that it's not right. It's not what you thought it it would be. Yeah. And I'm, I have also learned that there's a few more things I want to teach you because I was doing, I was trying to do examples that didn't use anything we hadn't done.
And I realized that we're missing some fundamental pieces that had completely slipped my mind, like say the ability to do mathematics. We forgot that. So that's, that's not on the agenda for today, but that is, I have added that to the, I've started to create a list of silly things I forgot early on and we did Boolean stuff, but we didn't do the obvious next step, which is math.
So that's, you know, you do need to do that from time to time, you know, add one.
It seems like I should be able to do that.
[1:22] We've been talking a lot about the fact that I can't add one to the number of podcasts I've done. So yeah, that's a good one to do. Yeah. The other thing I completely forgotten about on my mental map is that bash doesn't only have arrays, it also has dictionaries, which it calls associative arrays. So trying to cram arrays and loops into this episode and then also get associative arrays in was a terrible idea. So all arrays are next installment. But the other thing I had forgotten was quite how many loops bash has. Four. We're going to learn about four types of loop.
[1:59] So that is sufficient I think. And the great news is, they all provide a nice way to do a common thing.
So in theory you can simulate every loop on planet earth with a while loop.
That's true in pretty much every language.
But it's often you get much nicer code when you use different looping constructs and you get code that reads more like English.
And that will make future you very, very happy.
[2:29] Okay. So you can do it in a way that's not wrong, but it's not as elegant and good looking and logical looking as it could be.
Yeah. Which I would, which the fancy pants word I would put on that is maintainable.
Right. Because I don't like it when people say, oh, you're just wasting time.
I was like, no, I am making this code maintainable.
And I promise you in five years time, when there's an emergency and we have to fix this in two minutes, you will be very thankful this code is maintainable.
I get a grumbling. Okay, fine. It's an investment then. Yes it is, not a waste of time, an investment.
Anyway, I'm getting ahead of us.
So, we will be learning about while loops, until loops, for loops, and something that's sort of kind of a loop, because it does go round forever, a select loop.
And I have never come across anything like a select loop in any other language.
All four of these loops these loops have a very, very similar structure, which is very pleasing.
So if you remember when we did if there was the if keywords to start a conditional and then we had the then elif else and fee commands to control the conditional.
[3:46] Define the code blocks. Well, for a loop, you have less that you need to define.
You don't have this concept of an, an, an else, right?
So what you have is the for loop kinds, and then they all, they all, four of them use do and done.
So while something do, done.
Which again, it is clean. So what, so while whatever do done until whatever do done for whatever do done, select whatever do done.
[4:21] Okay. Okay. So the while loop is the most generic loop. While some condition is true, keep doing these commands.
So you're going to have while and then you're going to have your condition and then between you're doing your doing you're going to have a list of things to do and as long as the condition evaluates to true, we execute the commands, we check the condition again, we execute the commands, we check the condition again and we keep doing that as long as the condition is true.
[4:49] So could you make an educated guess as to what an until loop might be for? it's false.
Or no, no, as long as it's false. As long as it's false. Or until it becomes true.
So a while... Actually sounds backwards to me, but okay. Well, it's an inverse, right?
And until is the opposite of a while. So a while does something as long as something is true.
So while something is true, we keep doing this.
And until loop is keep doing this until something happens.
[5:23] So the most common form of until loop is to wait for something that takes time and you don't know how long you might have an until loop that just keeps checking, you know, check, wait five seconds, check, wait five seconds.
Oh, thank goodness it's finally true. Now I can continue my code or okay. That makes sense. Asking the user for input. I want an integer. No, really an integer. No, really an integer. Oh, thank goodness. Right.
Right. So you find that quite useful. Now I'll be able to remember it.
There you go. The for loop is for methodically making your way through a list.
If you have a list of things you have to process, a for loop is probably what you want because a for loop will start at the start of a list, work its way through and then finish.
And the last one, the select loop is, it's an infinite menu.
It presents you a list of all the possible options, lets you choose one, executes the loop for that value and then gives you the list again.
And it will keep doing that until your code tells it to stop.
[6:27] So it's specifically for user interaction? Specifically it is a user interactive loop.
So it is used in terminal apps that present you with the menu.
They're not as popular these days, but you used to log into something like, before all of our switches and routers had web interfaces you would tell that into them and they would give you this menu, you know, choose one to set your DNS server to choose two to do whatever, and then you would do whatever and then it would just ask you now what do you want to do and it would give you the same menu again choose one for your DHCP, you know, whatever.
Are what a select loop is for.
So basically we ask the user we do what they said and then we say hello what would you like now and then we keep doing that so cool.
So as i said the structure is always the same loop command followed by whatever arguments that loop command needs followed by a do then as many commands as you would like followed by a done.
So that is under all that shape which is very pleasing that they're also similar.
The other thing we have is that all three, all four of them support two flow of control commands which they exist in JavaScript and we have talked about them and I adore them but I don't know if many people use them.
They are continue and break. Do you remember what continue does in JavaScript?
[7:54] I don't remember the context for it. So in a loop, in a loop in JavaScript, whether it be a while loop, a for loop, a for each loop, if you use the keyword continue in JavaScript, what does it do?
I don't remember. Okay. But thankfully it does the same thing in bash, which is nice for people to remember.
So when you're in a loop, you have a bunch of commands.
The continue command will skip everything else left in the current loop and go on to the next iteration. So it won't exit the loop, it'll just jump to the next cycle.
[8:31] So it's very good for skipping things. So imagine you're looping over a file and you want to skip blank lines. At the top of your loop you could say if square bracket square bracket minus z, my variable name square bracket square bracket, do, sorry, if then continue phi.
That will mean that you go into the loop, you say, is this an empty line?
Yes it is. Skip on to the next iteration.
And then all the code below is ignored for your empty lines.
It's much easier than putting everything else in an else statement, especially if you have five or six checks to do, right?
What if you're checking for empty lines, you're checking for comments, you're checking for something that's invalid.
If you have lots of different checks, if each of them is just a simple if statement with the continue, your code is much cleaner than if this goes wrong, else if this goes wrong, else if this goes wrong. You end up with this really horrible mess otherwise.
So the continue command is fantastic for short circuiting a loop around a loop.
And the break- We weren't talking about conditionals, we were talking about loops.
And all your examples of continue were just in a conditional.
Okay, so you want to loop through something to process it, right?
So you're going to go around the loop an amount of times, right?
Could be 10, could be 100.
So you're going to have, say, 10 lines of code for do what I want to do.
[9:52] On those ten lines of code you're probably going to have some conditionals right if whatever i'm processing is like this do this otherwise do that.
If you meet a condition that says i'm done here i don't need to do any more work in this past through the loop then you would say if whatever the heck is going on continue.
I know it is jump you to the next thing.
Okay, I think I see it now. Got it. Okay. Okay. And we do have examples. So you will see these in action. And continues big brother is break. It just means I am so done here. I'm leaving the entire loop. I don't care if I was supposed to go around another hundred times. We are leaving this loop. This loop is over. So break is a real we're finished with this loop. I very rarely.
So it would definitely require a conditional to trigger break.
Yes. If you run into this situation, abort, abort. Yes, exactly.
So yeah, so continuous like stop this one and break is just stop. If that helps. Okay.
Yeah. So let's start with the while loop because it's the most generic and it's possibly the one I think you will tend to see most.
[11:06] So just like with the if command, you say while space, and then you basically provide a command, and it's the exit code of that command will determine whether or not the body of the loop gets executed.
So the stuff between do and done only gets executed if the command after while gives, you a successful exit code.
Which is zero. Which is zero. Exactly. So, okay.
And it will, so it will, the condition is checked. So the command is executed and we check the exit code.
If the exit code is success, we do the content of the loop. If the exit code is failed, we skip the loop.
We never, we execute the loop zero times, right?
Assuming we get a success on our first attempt, we execute the code of the loop.
And then we go back to the top and we run the check command again.
So whatever was out of the wild, we run it again. We see whether we got another success.
If we've got another success through the loop, we go again.
And we keep doing that until there is not a success.
And then we jump to beyond the done. So then, you know, we continue executing our script after the end of the loop.
In other words, after the done.
That makes sense?
[12:20] Yeah. Yeah. Perfect. So possibly the most common use of the while loop is for reading a file's content line by line because you don't really know how long it is so a for loop is a very bad fit. But the while loop when combined with our friend the read command that we've seen before will cycle through line by line by line until there's no more lines. So we have seen that read can be used to read from standard in. And so if standard in hasn't been jiggered with for want of a technical term, then standard in is connected to the keyboard. So when you ask read to read something from standard in, it comes from the keyboard. But if you, jigger with it, standard in can be anything. So the pipe command for joining two terminal commands. What it does is it takes a standard out from the command on the left, which would normally go to the screen. It diverts it and turns it into standard in for the command on the right. So what would normally the keyboard is not the keyboard, it is in fact the output from the previous command. And so we can use the read command to pull the content of whatever was, whatever's on the other side of the pipe.
[13:43] And what we didn't really say when we used read for reading from the keyboard, but it's kind of implied, is read goes one line at a time. You hit enter, and that took the value and brought it into your script, because enter is the end of a line.
So if you use the read command and you pipe it five lines of text, the first time you run read, it will read the first line.
And then it will stop and it will give an exit code of success if it did read a line or fail if it didn't read a line. So can you see how a while loop in in combination with a read command can let you cycle through a file.
[14:23] Yes, yeah that makes sense. So that is the single most common.
Now there is one little caveat here.
By default, because it's expecting you to type stuff in on the keyboard, by default the read command obeys escape characters.
So if you want to type into the input to read a new line character, you can say backslash new line and it will accept that as input instead of ending the line.
But if you're reading the content of a file, it could contain actual backslashes. So you want to tell bash to read without sort of to repress, in my mind I call it repressing the escape character. So the minus aura flag basically means I want the content of this file and I don't want you messing with it. I don't want you turning backslash quote into quote or backslash new line into new line. Just give me the actual characters that are in the actual line of text, please.
Okay. All right. It's just a habit you have to get into. Read minus or.
[15:26] So let's stop being all hand wavy. The first of really quite a few examples in this installment, I went up as far as the letter G.
So I don't know how many. Oh. A, B, C, D, E, F, two. Yeah. More, way more than five. Anyway.
So our first example, we're going to read the content of slash ETC slash hosts, which is a file that exists on every flavor of Linux on the Mac, which is why I've chosen it.
[15:53] It often doesn't have all that much in it, but anyway. In there is where you get to define mappings of IP addresses to names that exist even when DNS is broken.
The file allows the OctoSorp or the pound sign to be used as a comment.
So we're going to write a little script that prints out the content of the host file, but it ignores or comment lines, which gives us the opportunity to play with our continue command in real, world.
Okay. So you will find the code in pbs146a-whil.sh. So we have our usual shebang line, then we echo out a message, your computer has the following host entries.
And then the first thing we do is we cat the content of VTC hosts into a pipe.
And on the right hand side of the pipe, we have a while loop.
So we cat ETC host pipe while, read minus or, and then we choose the name that we want to read the line of text into.
And so we are going to read the next line of text into a variable named hosts entry.
[17:05] Okay, so just a reminder. Can I say back what that means? What you just said? Please.
So cat is basically saying get the contents of this file. Correct.
And the file we've chosen is slash ETC host and then use the pipe so that it becomes the text that you just pulled from that file becomes the text that's standard in to the while loop, which is going to read and we're going to say minus R because we want it to repress thinking about escaping a special character so that it listens to it.
And we're going to put all of that into each line will go into a host entry.
Correct. Will they be added to host entry or they become host entry for that instant in time?
For that pass through the loop until the next time you call read, right?
So every time you call read, it replaces host entry with the current, with the next line it got and the next line it got and the next line it got.
And as long as it gets lines, it does two things. Uplate the variable, give an exit code of success.
The variable give an exit code of success. And when it runs out of input, it doesn't update the variable, and it gives an exit code of fail, which will end our loop.
So I should have said more than in my description, because I didn't understand that.
You said read looks at line by line. So it's not reading the whole ETC host file.
It's reading it once over and over again until it runs out of lines to read.
That's what throws false, the executive one.
[18:34] Correct. Yes. Which has the effect of ending the loop. So in effect, So we started our while loop. Yeah.
So everything between do and done is going to get executed once for each line in the hosts file and we can access the content of the line with $hostentry.
[18:52] So the first thing we do after our do is we check if the line is empty because we don't want to waste our time printing an empty line.
So we say if square bracket square bracket and then we use the minus Z operator for checking for emptiness or for checking for zero-ness, I guess, if you want to mnemonic.
Did we already learn that? Minus Z means?
We did. We did. We learned about it last time, but we learned about a lot of operators.
Operators. So I would, I imagine you will end up looking back at the previous installment as a little crib sheet.
And I imagine you'll make friends with the ones you use most often because everyone's coding style is a bit different.
So everyone's going to make friends with different operators.
I much prefer a minus Zed to checking if something's equal to the empty string.
I don't know. I just prefer it that way.
It's not wrong or right. Right.
[19:45] It's this is how my brain does it. So if minus Z dollar host entry says, so for this line that we just read, because host entry was the variable name that we created for the one line we just sucked in from ETC host, if minus Z, meaning if this one line is empty, then continue.
Then you've got to continue. So it says, don't even do the rest of this thing.
Start out, go to the next line.
Bing, bing, bing. So we've short circuited the rest of the loop.
The next thing we do is we have another F statement. So this time we're going to take host entry and we're going to echo it.
So echo just means print it out and then we use the pipe to shove the content of host entry into the egrep command which lets us check for a pattern.
And the pattern we want to check for is starts with the octus orp symbol, the pound symbol, whatever we're calling it today, the hash symbol.
We haven't said that word yet.
So, if you're wondering why a minus q?
[20:41] Well read it out loud because they haven't they don't know that there's a minus Q it says if echo dollar-host entry pipe egrep minus Q and then the starts with octothorpe.
Yes so normally you would use grep to show you to show you the lines that match a certain pattern, but we don't want to print out to the screen the result of this grep we just care about the exit code and grep will give exit of success when it finds at least one thing and fail when it finds nothing. So minus Q says don't bother printing it out. I don't care what lines you found.
I just want your exit code. So it's Q for quiet.
[21:23] Oh, okay. Okay. So you're saying eGrip would have printed it out.
It would have printed it out, which is very annoying. This I know because the first version of the script, I forgot the minus Q and then I put it in.
Back me up again. What is the purpose of this script? This is going to be to find everything that isn't a comment.
So the reason, precisely, so the actual entries in the file.
So an empty line is an actual entry.
And a comment is not an actual entry. Precisely. Okay.
And this was a way for me to show you the power of continue.
And to show you the power of loops.
So I spent a bit of time picking this example. So if we haven't fallen through either short circuit, then we arrive at the last line of of code inside the loop, which is simply echo a star sign to make ourselves a markdown style bulleted list, done our host entry.
Done.
So if you run, you will see probably on a new Mac, you'll probably see two entries.
Basically an IPv4, actually no, you see three entries, an IPv4 for local host, an IPv6 for local host, and then the broadcast address for broadcast host.
[22:38] I have localhost, broadcast host, and localhost again. Yes. So colon colon one.
Yeah, that's that. That is the world's shortest IPv6 address.
That is literally the shortest IPv6 address.
So there we go. So that is an example of a while loop in its most common forum, reading through lines of text from something. So in this case, it was from catting a file.
[23:02] Let me describe it from the top again, because we didn't actually finish it very much. So you, said echo your computer as the following host entry. So that's what we're going to see spit out on the screen. Then we did the cat ETC host. So we get the file and we pipe it into while read-r host entry.
So it's going to pull that one line, then it's got a do and a done at the big picture.
But inside that, we want to skip empty lines.
So we do the if minus z dollar host entry. So if it's nothing, then continue.
So go to the next line.
We have another if then, which we didn't actually describe the if then.
But the if was to take a look at the host entry and using eGrep, quietly find out If it has an octothorpe at the beginning, if it does, then continue.
Otherwise, the next thing that's going to happen, we don't have an LF or anything, but the only other thing it can do is echo and a star for the markdown dollar host entry.
Perfect.
[24:01] Okay. Right. So again, just to- I didn't have to make that file executable to run it from the zip file.
Because I did before zipping it.
Okay. Thank you. Yes. So just to draw your attention again, I'm going to keep saying this because it confuses me, and I've been writing these scripts for years, therefore I know it's confusing our listeners.
So the read command, we pass the name of the variable, host entry.
When we go to print it or when we go to echo it, we have to say $ post entry because remember where a dollar means value of.
So I'm just repeating that for repetition sake. So it's just value up.
As soon as I saw it, I went, wait, oh, right. But I had the argument in my head.
[24:48] Yeah. I'm also just drawing attention to the minus Z from last time.
It just means check for an emptiness basically.
So minus Z will work with arrays, which we haven't met yet, and strings.
And I believe it also sees zero as empty. So it's kind of like a catch all for nothing. All powerful.
Yes. It is a powerful idea of zero-ness. And then of course the continue command is the other thing I want to draw your attention to.
And I see a terrible typo here. Host Eternity.
I can't even pronounce my typo. You got it. Good.
Because that damn lost on that one. And if I'm going to make a note to myself that I should put a link in the show notes here to the Taming the Terminal episode on eGrep.
[25:31] That probably will help people who have not done Taming the Terminal first.
So the egrep command accepts from standard in some text and it checks it against a regular expression in PCRE format.
So the hat symbol means starts with and then the octosor means the octosor.
So we are literally checking to see if the host entry starts with the octosor.
Right. So I've spent a lot of time on the while loop because it's the most common and because all of the other ones are very similar. So we don't have to spend nearly as much time because I can just say like the while loop. So let's immediately jump into our first new friend which is going to be the until loop. So until is exactly the same as while not.
But I find while not hard to read. So I will always use until in languages that support But it is literally a while not loop, if you want to think of it that way.
And the most common use of while not is for us squishy humans.
[26:37] So the next example, I've been a bit arbitrary here and people will complain at me slightly that names can have dashes in them and stuff, but I don't want this to get too complicated.
So the script example B is going to expect the user to enter a name and then it's going going to greet them by name and it's going to check that they really have entered what it considers to be a name.
And to make it a realistic example we're going to say you can either give me the name as a command line argument or I will make you type it in but no matter how you give it to me if you give me garbage I'm going to ask you again.
So if you pass it as the first argument and it's not valid I'm going to ask you.
If you don't pass any arguments I'm going to ask you. If you pass me the correct name as the first argument then I won't say anything.
The script will not prompt you, it will just greet you. Does that make sense?
Yeah. Yeah, I think so. Okay, so again it's pbs146b-until.sh.
We have our shebang line.
And the first thing I do is I simply assign a new variable named name and I give it the value of $1. In other words, the value of the first argument gets put into a new variable with the name name.
[27:58] And that may or may not be empty, right? Because there may or may not be a first argument. Doesn't matter.
So we then go to the until loop, where we are going to keep asking for a valid name until we get one.
So we say until, and then just like with the while loop, we need to give it a command, and what's going to matter is the exit code of the command. But in this case, if the exit code is fail, we do the loop.
And if the execute is success, we don't do the loop.
It's an opposite. It's an upside down world. So again, we're taking our name variable and we're piping it into e-Grep.
And the pattern we're looking for is, starts with an alpha character.
So not alphanumeric, alpha, which means you can type in accented characters.
I was friendly enough to foreigners to do that.
[28:49] Followed by one or more of, so the plus symbol means one or more of, followed by end of the string.
So start of string, one or more letters, end of string is the pattern for a name.
Okay. So the, so the artist formerly known as Prince wouldn't be able to do this, but. Yeah.
As I say, it's not realistic. It's the point is to have a condition on the input and that's like that.
This will do.
So, okay. So, so the first time you run it, it's going to be false because you haven't yet done the do loop.
Well, it might be true. Right. If you pass me in a valid name, then the first time through the loop it will not go through the loop.
[29:30] That's right, because you can add the argument after you say to run the command. Exactly.
And we will have taken it and put it into the variable name.
So when we echo $name, it will already be valid. We will pipe it to egrep.
Egrep will say, oh yeah, I find this pattern. Until will say, oh, you succeeded.
Then I shall do nothing.
Because remember, until is upside down world, success means fail.
Think of it like 1984.
Peace is war. Whatever way you want to put it. Anyway.
So inside our do we simply have read minus p what's your name and we read it into the variable named name. So minus p means prompt. So in other words, we will type the text what's your name?
And then you will have to type in your name.
And it will go into the variable named name.
So this is straight from. Why doesn't name have a dollar sign on it?
We are specifying where to go, we are not saying give me the value of.
[30:29] So at the beginning of this little script it says name equals dollar one, but that's only that'll only do something if it got a name.
Well, okay, well either way it could contain an empty string is what that means.
So name either contains some text or the empty string. name does exist.
But you can write over name. Correct. So that's what we're doing.
So read minus P is going to write over name. So read expects as its first argument.
Sorry. Yes. His first argument, it expects the name of the variable to write to.
So we are writing to a variable named name.
Okay. And what's the minus P again? It's the prompt.
It's the bit of text that will appear before the blinky cursor.
[31:13] Okay. That's so backwards. you're saying read something that I'm about to cause to exist minus p prompt what is your name that then goes into this variable.
Yeah. So read what prompt where. So read what where. I don't see this backwards, but I don't know.
Maybe that helps you.
Read what where is how I think of it.
Okay. And that's inside. That's the only thing inside the do done is just that read.
So then we'll just check. Did you give me what I wanted?
Have another go. you give me what I wanted, have another go. And until you give something valid, in other words something that successfully meets the e-grep, it will keep doing that. Round and around and around you will go. And finally when you give it something that matches the e-grep, the loop will skip over and you will end up with the echo statement at the end well hello there dollar name smiley face.
[32:07] And I confirmed that it keeps going if you give it a 1, a parenthesis or an accent, but But if you give it an accent at E, it says, hello there, E.
Perfect. Which is why. So square bracket colon alpha colon square bracket means any letter, including weird ones in other alphabets.
Which is cool. It's kind of an important regular expression because A to Z as a character class is a valid regular expression.
But unless you're actually sure that it's really just A to Z, it's actually not right Because accents do exist outside of us English speaking people, you know?
[32:46] I did find it funny when you said to take care of foreigners.
Like I'm in the United States and you're an island. Who's a foreigner?
That is, yeah. Okay. That's a fair point. That's a very fair point.
Just languages that use accents in names. Yeah. Yeah.
Okay. So that's the until loop. It really is just an inverse while loop.
Like you could rewrite that code with a while not.
But like I say, until is so much easier to read. Until it's valid, keep doing it.
So then we come onto our friend the for loop, whose job it is to do something over a set of things.
So the, okay, so the way the for loop works is the first argument we give the for loop is going to be the name of a variable.
The second argument is the keyword in. And then all other arguments are going to be what the loop loops over.
So the first time through the loop, the first thing after the end will be put into the variable with the name you gave it as the first argument.
The second time through the loop, the second thing after the end goes into the variable.
Third time through the loop, the third thing after the end goes into the variable.
And you keep doing that until you run out of things.
So in is the keyword. I am. It's literally in the letter.
So for space and name you've chosen space I and space your values.
[34:11] I can read that and I can hear you saying it. What does in mean?
It pretend it's a symbol, but it's it's a marker.
What does do mean? It's it is the language says you must type the characters I.
It is the rule. In must be to like to look inside it.
It's it's just a marker. It's just it's a marker that makes English sense for name of variable in some set of things.
It's it's a marker. It's a it's a placeholder. So we've got something to the it's for something in something.
What is what are the two somethings? What are the which one is which so the first something is the name the variable will have inside the loop?
Name the variable. What variable? Okay. So the thing is, everything after the end is going to be stepped through one by one by one.
When you're stepping, what do you call the current thing you're stepping?
Well, the answer is whatever was on the other side of the end.
[35:20] So for I in one, two, three, four, the first time through the loop, I will be one.
The second time through the loop, I will be two.
The third time through the loop, I will be three.
And one, two and three will be called the word that you get put between four and in. Yes.
While you're in that step. So four pancakes in waffles dot HTML.
Okay. Waffles dot HTML is one thing. So the first time through the loop, the variable waf pan...
Ah, what did you call it? Sorry.
Sorry. For pancakes in waffles.html, I'm picturing waffles.html has a whole list of stuff in it.
Ah, okay. If waffles.html has a whole list of stuff in it, then you're going to have to do a cat or something to pull the whole list of stuff out.
Okay. So. Okay. No, no, no. I think I have an example for dessert in pancakes space waffles space popcorn.
Okay. Okay. So we're not reading a file here. We've just got a list of stuff.
Correct. So the everything after the in space delimited will be the values that go in.
So it's arguments, right?
Just it's a command with arguments.
So first argument after in. Okay.
Yeah. Because everything's a command.
[36:49] Now so actually, yeah, the dessert example is actually a good one.
So if you say for dessert in pancakes, waffles, popcorn, the first time through the loop, dessert will have the value pancakes. The second time through the loop, dessert will have the value waffles.
The third time through the loop, dessert will have the value popcorn.
Okay.
[37:06] Okay. Now in your example. Aha. So I have some more English to say.
So the list of arguments supports shell globs, right? So if you have the command ls...
Okay so i'm about to explain so when you have the command ls you know you can say ls star.
I'm not behave as if you had typed in every single file in the current directory.
What's actually what bash does is it. The star character expands into everything that matches which is actually put their eyes.
First file space second file space third file space fourth file so, Those expansions are called shell globs.
[37:53] So you can do for file in tilde slash star and tilde slash star will actually expand into documents, downloads, whatever, a desktop, whatever pictures, pictures, videos, movies, whatever Apple calls them. Right.
So each thing in tilde will actually appear on that list and then each one will become the variable one by one. It's just the name of that thing.
Yes. So the thing between the four and the in. It's inside that folder.
Just pictures. The word pictures becomes.
Yes. Yes. So our example is PBS 146c for files.sh.
And we have our usual shebang line, echo, the files in your home dear, colon, and then we start our for loop. So for space file space in.
So for is baked in and in is baked in. And I have chosen the name file.
And then what is it we're going to loop? we're going to loop tilde slash star, which bash is going to expand into whatever the heck is in your home directory, which is going to be different to mine.
And if you're on Linux instead of the Mac, it'll be very different to mine.
[39:17] Then we have do echo our markdown style star space dollar file, done.
[39:26] Okay. I think if I hadn't been reading the show notes, what you were trying to explain with for and in would have made a lot more sense. Because I kept looking at for file in tilde slash star. What? But now that you've explained it now I've backwardsly caught up if that makes any sense.
[39:43] It does. So again, if you run it, you will see it just lists the content of your home directory.
[39:48] One line at a time with a little markdown bullet point in front of it.
Yay cool. So the other very powerful thing you can do after the in is you can have a command that outputs a bunch of words and then loop over those.
There's lots of commands. Unfortunately it's very hard to find something that's cross platform so with my real world hat on, Modern versions of Red Hat Linux use a firewall called firewalld and it's controlled with a command called firewall-cmd and firewall-cmd outputs the information as space delimited values.
So I am forever looping over the output of the firewall-cmd command.
Like forever doing for service in, dollar sign, open round bracket, then my command, round bracket and my command would be something like firewall d, firewall cmd minus minus list minus services.
And then I will get back ssh, http, https as the values for my for loop or whatever is enabled on that server, whatever the firewall is configured to allow on that server.
And then I will do something. I'm forever looping over the output of firewall cmd.
So any command that outputs text can be used after the in as long as you use the $ open round bracket your command close round bracket which basically means you get the value of the output of this command.
[41:15] And it will just, every time it meets a space it'll just say oh you're the next thing I have to worry about and it will loop through them.
[41:21] Which is strangely powerful. So like I say it was hard for me to find an example that will work for everyone whether they're on a Mac or whether they're on Linux but I did find a command, the groups command lists every group that you're a member of separated by a space.
So our next example is not named in the show notes. That's a terrible omission by me.
So the actual script is going to be D146D-4command.sh.
[41:54] Usual shebang line echo you belong to the following groups, colon four group space in space dollar open round bracket groups close round bracket.
So that is saying execute.
So if you just type groups, it, I tested this because I was trying to understand it.
If you just type groups in a terminal, it just lists all the groups that you said.
So that's why you're saying for group in dollar open parenthesis groups.
So as it spits out this space delimited list.
Exactly.
And then every time you go through the loop it'll be the next value in the list and you will be calling it dollar group. So for group in dollar open round bracket groups close round bracket do echo our markdown star dollar group done.
[42:45] And that will print out. That's actually pretty cool. Very powerful.
I am always fussing around with my groups, unfortunately. Yeah, so.
I didn't realize there were so many of them.
But there are on the Mac. Particularly more modern versions of the Mac.
There's even more of them. Anyone that starts with an underscore is a super secret Apple group.
And the other ones are normal. But there's also a bunch of like com.apple.access.unerscore screen sharing.
Which is also an Apple one, yeah.
This account has allowed you to now do screen sharing.
And SSH. Yeah, I don't have that particular one. SharePoint!
Com.apple.sharepoint.group.3 and.2.
I don't do SharePoint.
[43:30] Microsoft did that. I was going to say, there's a non-zero chance you have OneDrive installed, and OneDrive is SharePoint.
Yeah, okay. That's probably it. Alright.
[43:41] I see ClamAV. What the heck? What did ClamAV get on there? Don't even ask.
You haven't done a clean...
No, no, this is my brand new, no, no, this is my brand new M1 Mac.
I did not install Clam AV. That group came into being somehow.
I don't think Clam is really... Oh, interesting. That group exists. Oh, it's...
Anyway, yeah, lots of groups. The point is you can...
So the most common use of while is to loop over a file.
The most common use of for is to loop over a command's output.
But it can also do more traditional for loop things.
So the for loop actually has an entire other optional syntax called the C-like syntax which I find confusing as all heck because it does something called Automatic Variable Expansion, which means you don't use the dollar to get the value of i which breaks my head every which way, but it lets you write something that looks like C code if you squint very hard.
So if you want to loop from 1 to 5, you can in bash, and it is valid, say 4, space, round bracket round bracket, i equals 1, semicolon, i less than or equal to 5, semicolon, i plus plus, round bracket round bracket, do, echo, the value of i is dollar i, done.
[45:09] That is valid bash.
[45:11] I am not a fan of this approach, but it is what do you like about it?
I is less than five, not dollar I. I.
[45:24] That's I though. I gets to do whatever I want. Or I could put pancakes in there and it would work.
Cause I'm actually creating a variable and then accessing it twice.
And I don't have to use a dollar while it's inside the two, the double roundy brackets because inside the double round brackets you have this magic variable expansion, But later on, inside the loop's body, it's still Donorai.
I don't like it. It's also very verbose because there is a better way. There's a much better way.
Okay. So bash provides an operator called the range operator, which is open curly bracket, a starting value dot dot and ending value close curly bracket.
And it will expand into a space separated list of numbers between the first one and the last one.
So the range to demonstrate it, I've put a little table of examples.
So open curly 1 dot dot 5 becomes 1 space 2 space 3 space 4 space 5.
5 dot dot 1 becomes 5 space 4 space 3 space 2 space 1. So you can loop through in either direction and it works with letters.
So a dot dot f becomes a space b space c space d space e space f.
[46:40] So, why would you bother with four bracket bracket i equals one semi colon i is less than or equal to five semi colon i plus plus when you could simply do something like four, n in open curly one dot dot five closed curly and then n will become nice and clean.
So as an example we have PBS146E forRange.sh which is going to print out all of the valid hexadecimal characters by using two range operators.
So we say for space car space in space open curly 0.9 closed curly space open curly a.f closed curly.
So the first range will become 0123456789 space abcdef. So the end result is perfectly spaced 0 to 9, A to F. In other words, every valid hexadecimal character.
[47:39] Now, did you have to put a space in between the curly brackets for it to get a space there?
Yes. Otherwise I would have ended up with a single loop entry called 9a. 9a.
That's what I was wondering about. By the way, when he said car, he means a variable he's created called char.
For character. Like character.
Yeah. Now, in Bash version 4, which Apple have not deigned worthy of sharing with us, there is, There's an optional third parameter, I guess, to the dot dot operator where you can say start dot dot end dot dot step.
So if you want to go in twos, you could have dot dot two.
Doesn't work on the Mac. We are on version three.
But don't worry, there is a terminal command that can do sequences in every way you care to imagine. It's called SEQ is the command, sec for sequence.
If you do the man page it can do way more than I'm showing you here.
[48:37] If you give it a single argument it assumes you want to start at 1 and count up to that single argument. So if you say sec 5 you get 1 space 2 space 3 space 4 space 5.
If you give it two arguments it assumes you'd like a range.
So if you say sec 10 15 you get 10 11 12 13 14 15. If you do it in reverse it's perfectly happy too.
So sec 5 1 will give you 5 4 3 2 1.
And if you give it three arguments, the first argument is your starting point, the second is your step, and the third is your finishing point.
[49:10] So sec 0520 becomes 05101520.
[49:15] So the middle one was the step? The middle one is the step, which is mildly annoying if you're used to writing in bash 4.
But the sec command is portable. The sec command will work in all versions of bash and it will frankly work in sh because, the sec command has been around forever.
So if you want to, if you need to do funny sequences the sec command is your friend.
It's very powerful and it works on all versions of bash and sh and zsh so it's portable as well.
So as an example we have a little script called four step range.sh which prints out the even numbers between 0 and 20 by simply saying for n in $sec0220. In other words, start at zero in steps of 2 as far as 20. And then we say do echo our little markdown star $n.
And done.
[50:14] That's fun that is fun and i can say i really like the range operator because most of the time you going in steps of one.
So the range operator works a lot of the time and it makes for such friendly code for i in one dot dot ten so nice.
Okay so i did in javascript now i know so that brings us on to our final weirdo friend the select menu loop.
So, Select works like for only instead of it going through everything in order, it asks you which one you'd like and then only does it with that one and then it gives you the list again and waits for you to tell it what to do next.
So the example I have here is our pancakes example from earlier actually.
So the example is pbs146g-select.sh and it will ask you for what dessert you'd like until you tell that you've had enough, which gives me an excuse to use the break keyword, which is of course the only way to get out of here apart from the exit keyword, which really gets you out.
So we have our usual shebang line and then we say select dessert in. So again, it's dessert is the name we're choosing in and then come the values. So I'm giving it the values pancake, waffles, popcorn and then quoted so the space doesn't break everything, enough thanks.
[51:39] And then we have our do. So inside the do we have if square bracket square bracket dollar dessert is equal to enough thanks, then break fee, echo, have some dollar dessert.
So when you run that you will be asked whether you like pancake waffles, popcorn or enough thanks, and it will put numbers next to each one automatically and you just type the number matching your choice and then you will get the appropriate echo.
And if you type four, which is enough, thanks. It will stop because the break will pull you out of the loop.
I like it. I like it. I think I would have said thanks for eating here.
Yeah, you get the idea, right? You know, it's some sort of escape clause.
[52:26] So I have a challenge for you. Oh, goody.
I would like you to write a bash script which takes input from the user in some way.
Well actually okay I'm going to be a bit more specific.
I want you to take input from the user either as the first argument or by prompting them.
But I want to get from the user a whole number that is greater than actually no just a whole number I think I saved which is good enough yeah Annie give me a number Then i would like you to print out the table the multiplication table for that number so if you give the number three the output should be one x three equals three two x three equals six three x three equals nine all the way up to ten x three equals thirty.
So if you run this again you give it five i want the five times tables to get the idea.
A little hint, the way I would like you to do the math is not the best way, it's the way that's the most portable because there's a terminal command called BC, which does not stand for Before Christ, it stands for Basic Calculator.
And you can either Google BC or Bing, or you can use MAN BC to figure out how to make the BC command do your math. Now the BC command can do the math you need to do here, a simple multiplication.
Oh, okay good.
[53:52] So we don't have to do the... We don't have to do the bit that I haven't taught us yet, which is how to make bash do the math itself. We're going to let the BC command do the math, but we will learn how to make bash do the math later.
So if you'd like some bonus credit, so by default I want you to go from 1 to 10, so the 5 times tables would be 1 times 5, up as far as 10 times 5.
But for bonus credit, I'd like your script to allow the user to optionally also specify how far to go.
So if you optionally tell it to go to 20, then I want you to go all the way up to 20x, whatever the numbers that they gave us the first argument.
So this means figuring out how to get it to put those numbers in as well.
Not hard coding one times.
It does. So input equals. Yeah.
[54:41] So I figured I want to give you exercise in the most important thing.
So you're going to have to make a variable, you're going to have to use the read command to get input from the user, you're going to have to deal with command line arguments, you're going to have to loop, you're going to have to print things out, and you're going to have to call a command and use the output of the command for something else.
So you're going to use the BC command's output for something.
So that's actually a really good sampling of everything we've done so far.
You probably have to check to see if it's a number too. You do, yeah.
So that's again, you're doing some conditional work there of some kind, whether that conditional is an if statement or whether it's part of a loop. Up to you, there's a lot of, there's an infinity amount of correct ways to do this challenge.
But you will have exercised a very big subset of what we've learned. This sounds fun.
[55:39] And not that hard, but I bet I get stuck. Well, that's the joy of that's why I chose this assignment.
It's not long, but it does make you use many concepts at least once.
[55:52] And since you haven't had much practice, I would expect this to take you.
You're going to end up with very few lines of code and probably many hours to get there.
And that is expected. An hour per line, right?
Yeah, exactly. That is expected and that is normal.
So at this point in our journey, we're actually making really good progress, but like I say, I realized as I was trying to come up with examples that we have some work to do. So, like, you know, love and marriage go together like a horse and carriage. Well, arrays and loops go together like love and marriage, I guess. We really do need to do them next. And it's been really, really hard to avoid using an array for all of the previous installments because arrays are so powerful in programming. And we should also learn about dictionaries because they are also darn useful or associative arrays as they're named in Bash World. So those two will keep us more than entertained next time because they are very important and I want to do them justice because combined with loops they are extremely powerful and you will definitely need them to start writing scripts that do real world problems. You need to be able to have arrays and associative arrays.
So that's where we're going next.
That sounds like fun. I like this stuff, Bart. This is really cool.
I'm having way more fun than I thought writing these show notes.
[57:15] I've been doing a lot of bash programming, but I've been learning about it piecemeal.
And now I'm getting to learn about it as a whole sane unit and telling a story.
And I'm learning so much writing these show notes.
So many things are making sense to me. Yeah. It's actually a very logical, a very simple language.
[57:36] But it's a bit weird. When I say a bit, what I mean is heck and lotter weird.
Anyway, here we are. So this is evergreen content, but I think this story will still work with evergreen content.
I got a mastodon toot from a guy who said he was really enjoying he's starting to do Taming the Terminal.
And he said, it's great, but Bart talks too fast. And so I suggested, I said, well, you can always go.75x.
And he wrote back and he went, yeah, okay, that helped. And then I realized what was wrong.
Same problem I had with listening to you on a podcast.
Smart speed does not work with Bart's teaching. So I was listening to an episode of Let's Talk Photography and I'm like, oh my God, Bart slow down. No, no, no, you just finished the last concept.
I don't have it cemented yet. Wait, wait, wait, wait, wait.
And then I went, Oh man, I bet I've got smart speed on.
So I wrote to the guy again and I said, do you buy a chance to have smart speed on in overcast? He said, Oh my gosh, this is so much better.
Yeah. I'll pause quite a lot. I, I make heavy use of pauses because I'm used to teaching in real world speed in, you know, in actual classrooms. Yeah.
[58:51] And smart speed goes, Oh, emptiness. We shall have none of that.
I guess we should have a backing track. Go listen to anything you've done where you're teaching and have that. It's horrible.
I was ready. I was going to call you and yell at you for why did you why did you do that episode like that?
[59:06] So anyway, I'm glad you noticed also that was a fun episode if it was the AI one.
The first day I forget. Yeah, yeah, might have been.
All right. Okay. Anyway, so until we get to meet our friends, the array and the associated array, 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!
[1:00:00] Music.