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 758 for February 4th, 2020. Oh, hello 2023. And I'm your host, Alasdair Sheridan. This week, our guest is Bart Bouchats with Programming by Stealth, installment 144. How are you doing today, Bart? I am doing good. It's funny that you tripped on 2023 because since this decade has started,
I can't type the year because my brain here is 2020 and it types 2020. So I've been typing 2021,
2022 and now 20203. I thought I was the only one. That's exactly what I've been doing.
Yes, because it's 2020. So your brain goes 2020. Oh, sugar. We're just going to add a one, a two and a three.
Exactly. So anyway, there we are.
So what the listeners won't know or care about, because this is evergreen content, is that you and I have had a small gap between part one and part two of this very, very related to instalments here.
So hopefully it sounds sensible when you listen to them back to back five years from now, but we are on part two of our journey into shell scripting.
I call it a journey. It's more of a brief holiday. We're paying a little visit, a tourist trip around shell scripting.
[1:22] So in the previous installment, we learned how to, you know, the basic anatomy of a shell script, shebang line at the top, and then your terminal commands one after the other after the other. And your comments with the pound symbols or octothorps or whatever we're calling them.
We learned that we can make variables. We learned all the weirdness about, you know, accessing our variables with double quoted strings, and we learned about single quoted strings and concatenating strings by just sticking them back to back without even a plus symbol between them.
What else we doing last time? I think that's sort of the bulk of it.
But and I'm going to interrupt you right here as a setup for what you're going to say next. After we worked on that, I was working on making mermaid diagrams and I thought, you know what?
I would really like to automate the way mermaid diagrams get created. I would like to have a shell script that creates my mermaid diagrams for me.
And I thought, OK, this is going to be great. And I had went to do it. And I said, I don't know how to send variables into my shell script.
[2:21] Yeah, which is the next one. And I ended up needing to know about something called exit code. So what are we going to learn about today, Bart?
[2:27] We are going to learn about those very two things, because obviously if you just put a bunch of commands in a file, it will do exactly the same thing every time.
Now, mostly you want it to do the same basic thing every time, but not exactly the same thing every time.
So you need some way of telling it. I want you to do this thing with this thing. And so we need a way of sending input and output.
Now there's actually a grand total, if you include all the inputs and all the outputs, there's actually a grand total of six different inputs and outputs if you count them all. So the obvious one is you can pass it arguments, which we're going to talk about today.
You can also, you can ask the user to type something in. So you can basically prompt the user and say, please give me a blah, blah, blah.
So we're going to learn about that today as well. And the other thing you can do in Terminal Land is you can pipe things into a command. We have done this many times where we, some command, pipe some other command.
Well, you can pipe things into your scripts, which also means that what have we got in terms of output? Well, you can pipe things out of your script through standard output.
There's also the standard error stream where your error messages go. So that's two outputs.
And then there is this weird thing called the exit code, which on the one hand is completely hidden, and on the other hand is absolutely critical.
[3:50] Because that exit code allows us to take different actions depending on whether or not our terminal command succeeded or failed, or even how it failed.
[4:03] Because one of the things a creator of a terminal command can do is define the meaning of different exit codes. So you can say that in my command, if I return with an exit code of 404, that means something doesn't exist.
Or in my command, if I return an exit code to 101, it means you type the password wrong. Right. You, you as a creator of the terminal command or shell script get to decide what the error codes mean and you put it in your documentation.
Anyway, we'll get to that later. So what I was looking for was something that would tell me, is it going to fail?
And that got into some trickier stuff, I think.
I think that's called temporal mechanics. Yeah, well, I wanted it to check to see if the command was even there that it was trying to call.
Which is something we will learn next week. There is actually a way of doing that. Okay, there is a very useful command called test, but test makes no sense until we know what we're going to learn today.
[5:02] Okay, test is is Was it someone once said, you know, the unix is simple, but you need,
to an LSD to notice the simplicity or something like the test command is is sensible, but only in the world of shell scripting.
[5:20] So we need to get a little bit, we're gonna need our feet a bit more wet in that world, and then we will come on to the joy of the test command, which is amazingly powerful.
So anyway, today we're going to look at three of the six possible ways of doing input and output. And the reason we're not doing all six today is because in order to actually effectively use the pipe stuff, we need to learn about conditional statements and loops.
And we can't read it in a recognition statement and loops this week, we need to do basic IO first. So we're gonna do half the IO, we then are loops and conditions, and then we get to finish off with the piping stuff, which in some senses ties it all together.
Because once you're into the piping stage, your shell script then becomes a first class citizen on the terminal, because the whole joy of the terminal is running your inputs through a sequence of commands.
Well, you can then start to chain your scripts together into sequences to do powerful things. So that's why we're finishing there.
Okay. Right. So with all of that out of the way, there is a zip file for this installment, but to be honest, I don't think a single one of the two files in that zip file is more than five lines long.
So you can probably just copy and paste, but for sheer convenience, I've added the two files into the zip file anyway.
[6:31] So the first thing we want- I don't know, one of them is 82 bytes, Bart. I'm not sure what you- Oh! Thanks for watching!
It's about a character a byte although some of them contain smileys that's two bytes for one smiley so who? Anyway, we will start with command line arguments because that is the most obvious way to push
information in and out of a shell script. So if you put a terminal command takes its arguments by having name of terminal command space argument space argument space argument. If you want to pass arguments to your terminal command you do exactly the same thing. But then the question becomes.
[7:09] Okay that's how I send it to my terminal or sorry to my script. When I am in my script how do I access them? Well the answer is there is a variable called $1 which is the first argument there is
one called $2 which is the second argument and it continues ad infinitum. I think it goes up to 256 but it continues for some time. And in case you're wondering why these computer scientists
sensibly started from one for a change, there is a $0. $0 is the actual command you use to call the script. So our first example, PBS 144A-ARGS.SH, has the simple line echo, open a double quote,
I am and then inside single quotes dollar zero comma my first arg is and then inside single quotes dollar one comma and my second arg is inside single quotes dollar two.
[8:04] So if we run that script with dot slash PBS one four four eight dash args that sh space pancakes space waffles that means that pancakes is our first argument and waffles is our second argument. It prints out I am inside single quotes dot pbs 144a dash args dot sh, comma,
my first jar is pancakes and my second is waffles.
[8:27] Perfectly sensible. I think I've seen this dollar zero, dollar one, dollar two nonsense in Apple script. I think it does it the same way.
[8:36] That is entirely plausible. I know very little Apple script. I know that if you do regular expression matching in JavaScript, you get dollar one, dollar two as well, I think.
[8:47] Okay. And I know when there are other languages that use them, it's a, it's a common thing, which yeah, so dollar one and dollar two, et cetera, are our arguments. Very straight. So we don't have to save the arguments to a variable name, they have a variable name $1, $2, $3.
[9:00] Exactly, they're just there for us to use, which is fantastic. The other thing we can do is we can ask the user for something.
So in fact, once we learn if statements you can start making your terminal commands really friendly and you can say I'll go look for an argument and if I don't find an argument instead of throwing an error I can just ask the user for the thing I wanted.
So you could say if there is no $1 then prompt the user to tell me their name or whatever So you can get very creative.
But the command we're interested in for getting input from the user is the read command, which is used for more than just reading input from the user.
But its default behavior is to read from standard in. And most of the time, standard in is connected to your keyboard.
That's not true when you're dealing with pipes, but that's something we'll talk about the ensoulement after next.
So for us today, standard in is the keyboard. So the read command's default behavior is to read from the keyboard. It needs one argument, which is the name of the variable it should read into.
In other words, if you ask me for something from the keyboard, where do I put it?
And you give it the name of the variable. The confusing thing to terminal newbies is that remember that the dollar sign is kind of saying, fetch me the variable.
[10:21] So the name of the variable doesn't have a dollar. The dollar is how you access the variable. So the first argument to go to read is not a dollar. My variable name. It's just my variable name.
And that's something else, which is also true when you create a dollar. No, so it's just variable name. But when you call it, it's dollar variable name.
When you sign it, the dollar. Okay.
Correct. And it's the same when you do with the equal sign, right? When you assign a variable, you say, you know, waffles equals pancakes. And then the variable dollar waffles has the value pancake because the dollar actually means fetch the value of.
Right. Okay. Okay. I think you told us that last time, but I think you should probably tell it to us every time.
I need to tell myself it every time. One of the most common errors I get in with my work hat on when my shell script doesn't work is that it says there's, there's no variable dollar dollar, whatever, because I've put a dollar sign in when I named the variable.
Which then means it's actually when I wrote, tried to access it, I should put $2 in it. Yeah, I do it all the time. I get it wrong all the time, which is why I keep repeating myself.
[11:22] So we could use the read variable in conjunction with the echo command we learned last time. And so we could say echo, what's your name? Question mark. And then we could say read space name,
right? And that would read the name into the variable name. So that's two commands to do what's kind of one job. I want to get the person to enter a name. So to save you having to use two commands,
the read command has an argument called minus p or a flag called minus p that lets you specify a prompt.
So you can say read space minus p what's your name space name and that will print to the user what's your name and take the answer they give and stick it in the variable name.
So the advantage that was just doing it all in one line instead of two lines? It's all on one line.
It also displays on the same line. So it's a little bit less cumbersome output because it's not a line of text. And then a blank cursor sitting on an empty line. It's what you want. And immediately the cursor is next to the question.
Oh, OK. Waits for you right there.
It waits for you right there, which is actually kind of nice. And so if you want, you can put a symbol like some people put like a little carrot symbol at the end of their prompts so that you sort of get a blinky cursor like you'd expect. Yeah, it's up to you.
I noticed that you also put a space after you said, what's your name? You put space quote that way when they write their name, it'll have a space in between.
[12:48] Correct, which I discovered after running the script once again. Well, that doesn't look good. So then I did it again.
[12:55] So we have our second example, which is just a little three line script. It says read minus P, what's your name into name, read minus P, what's your favorite fruit into fruit. fruit, and then it echoes out inside double quotes, high dollar name, comma have some dollar fruit.
And then we close the dollar, we close the double quote because the variable we called it fruit, but I want to make it plural.
So then I immediately stick onto the end of it, another string with single quotes with the S followed by space, followed by smiley.
And then I close my single quote. So that's two strings concatenated by just shoving them next to each other. So when I run that command and I enter Bart an apple, you get, hi Bart, have some apples.
And it beats my face. So that's a good reference one for us to remember how to do that concatenation you taught us last time. Precisely why I did it.
And it's something that comes up quite a lot actually playing around with those different strings and stuff.
So that's two out of our three methods of input for today. So the last thing I want to talk about.
What if my favorite fruit was bananas?
[14:01] You should have some bananas.
[14:04] Ah yes, pluralisation is surprisingly difficult in error messages. With my work hat on I tend to put S's in brackets a lot.
[14:13] Oh because plural might not be... Might be plural, might not. Doesn't matter, just moving on. There is an amount of, yeah. There has been an amount of error. I hope they're singular.
Anyway, it is a lot of error reporting I end up doing.
Okay, so the last thing I want to talk about, which is probably our biggest topic for today, is exit codes. So every time any terminal command finishes running, the last thing it does is it hands back to the shell.
So a shell runs commands on your behalf.
The last thing a command does as it finishes is hand back to the shell an exit code. Or if the command falls over in a giant big heap, the shell will make up an exit code of, I think, 1.
I don't know what happened there, but that guy just went away. I asked him to go do something and he vanished.
Error code. And so that exit code is a way for the command to signal what it did programmatically.
And so they're just a range of numbers from 0 to 255. Because you can't have 256. Anyway, 0 to 255.
And the person who wrote the command gets to decide what it means.
[15:28] So a lot of times when you look at the man pages for a terminal command, there'll be a section near the bottom called exit values or exit status or return codes or one of the very euphemisms for exit codes.
And it will just list the numbers and what they mean.
[15:44] So I just basically picked a terminal command at random because I happened to have done a backup recently. I just went man orsync to see what was in there.
[15:51] And lo and behold, at the bottom of orsync is a very long list of error codes. So error code zero means success. Error code 1 is syntax or usage error.
To his protocol incompatibility.
Error 3, selecting input or output files. Error 4, requested action not supported. An attempt was made to manipulate 64-bit files on a platform they cannot support them.
And it goes on.
[16:14] Actually, it's strange. I've got to go back and look. I had an R-Sync error that needed to say, your friend's house where you put your other Synology that you're backing up to using R-Sync had a power outage and I didn't come back up.
That's what it needed to be. Probably some sort of connection error. Error in socket IO, I'm going to guess. Probably error 10.
Yeah, I'm going to have to go find out. So anyway, they all have them. And the one thing that's in common always is that very counter-intuitively, zero means success.
[16:52] Hmm. And in almost all of computer science, zero means false or not or null. It's like not good.
And one means true or happy or one is true.
Whereas here one is just the first of another 254 error states. Everything that isn't zero is bad.
Zero means nothing went wrong. Everything else means something went wrong. And I have the choice of expressing that somethingness with these 254 possible numbers.
So in my brain, I remember this counterintuitive fact by never mentally calling them exit codes, I call them error codes in my head.
Oh, on purpose. Zero error. Zero error is how I remember that at zero is good. Okay.
Now, very carefully when I type things and when I write documentation and when I'm communicating with the nerds, I'm very careful to translate it back to the proper usage of the word. of the word, but in my head they're error codes. And then I remember zero is good. Zero error.
No problemo. All happy. Okay.
[18:00] Yeah. Yeah, that makes sense. So these exit codes are always returned to the shell, but we don't see them, right? When you run the ls command to have a look at a directory, it returned an exit code of zero unless you asked it to list you a directory that doesn't exist, so it would have returned you some other exit code.
But you don't see that, right? It doesn't print out the list of files and then a zero, right? It's invisible.
But it's not invisible. It's actually in a variable.
It's in the specially named variable question mark, which you access with $?
So if you say echo $? it will show you the exit code from the previous command.
Oh wow.
[18:42] Which is very useful when debugging things.
[18:46] And the exit code of the echo command will be zero. So if you type some command and then you say echo dollar zero, dollar question mark, it will give you the error code.
And if you do echo dollar question mark again, it will not give you the error code anymore because the previous command is now the echo command, which succeeded. So we'll be back to zero.
So you really do need to check the exit code immediately and you don't get a second chance because once you run another command, it's now something else.
So the exit codes, yeah, the exit codes are always there. Therefore you can always access them with echo dollar question mark.
[19:23] Can you do that inside the script? You can.
Because you've told it some command to do and you can, so you could do that as, as error checking maybe within a script.
Absolutely. You can. So you can either just do it in the sense of, I don't really care what went wrong. If something went wrong, do this.
Or you can use it in even a case statement in the terminal. Our bash has a case statement.
So you could actually say case zero echo. Yay. You know, and then a different case for each of the possible different. What is case?
I don't know what case is. Uh, sorry. Case is the equivalent of switch in JavaScript.
[20:04] So you would say switch a and then you can say case. It's like doing an if else, but instead of typing if else you just say case one, case two, case three, case four.
[20:14] So instead of saying if...
[20:17] For the case that the variable I'm switching is a one, do this. For the case that the variable is a two, do this.
It's like saying if x double equals four, do this. Else if x double equals two, do this.
Else if x double equals three, do this, right? really cumbersome to type out. So the switch statements that you say, switch X, case one, some code, case two, some code.
Oh.
[20:44] Yeah, I'm sure. Maybe I didn't talk about it in JavaScript. There was a lot of episodes.
I was going to say if I did, it would have been a roundabout I would guess episode 14 or 15. Which is a wee while ago. 42 years ago. Yeah, yeah, fair.
But luckily we all know that my mind is like a steel trap and nothing has slipped through in all these years.
Right, not a wine ball that you're trying to pour it into from a fire hose. Definitely not.
I do adore that analogy from your dad. Anyway, yeah, the point being you can absolutely use those exit codes in your scripts to make your script react differently.
Well, the most simple thing to do is to make it react to an error, just to make it do something sensible when anything went wrong.
Or you can use it to be very intelligent. If you're using a command with well-documented exit codes, then you can actually save $? into a variable and then really do some work with that variable and have a bunch of different if statements and whatever.
[21:51] It all depends on how important the thing is. If your script's whole job is to do a certain thing and react in a sensible way, then you may spend 10, 20, 30 lines of code dealing with the possible exit codes because it's really important.
Or you may just not care. You may just think, either it worked or it didn't.
And then you just write a very simple piece of code.
I'm stuck on that. I don't understand what it can do other than succeed or fail.
[22:19] Okay, so the command returns an exit code at its discretion. So it can use that exit code to tell you why it failed.
[22:28] Okay, but you talked about us writing the exit codes that we can write in it. No, not yet. Something. Oh, okay.
I will be saying that, but I haven't said that yet. Okay. So you asked, can I use these exit codes in my script? So in your, in your script, you might do something like, uh, or sing. I might do our. Or turn it in.
Okay. And our sink is going to spit back these predefined exit codes that the command our sink has to it. Okay.
Correct. And so if you're doing an R sync and it's really critical to your script's grip's functionality, maybe the functionality is like if Orsync doesn't work, try FTP.
[23:05] Or maybe the functionality is if Orsync fails for this reason, then email Ron because his power is gone.
If Orsync fails for this reason, email Steve because he's hogging too much bandwidth.
I mean, I'm sort of making it up as I go along here, but you may want to do different things if something like there is more to being broken than just is it broken, right? I think it's one of the...
When I put my work hat on, I think the thing I hate most is when someone comes to me and says, it doesn't work and they cease speaking.
[23:32] It's like, no, no, no. That is the start of something useful. What?
My favorite phrase is, hum a few more bars for me.
Yeah, exactly. Exactly. That is the perfect response because I generally just give a dirty look and sort of the gesture of, you know, continue.
Yes. Exactly, exactly. So anyway, yeah, the extra codes. The only thing worse is when they tell you some completely extraneous piece of information that takes them forever to explain that you already know has nothing to do with this.
I had a woman on the ship who was on the cruise we were just on who her phone couldn't get email and she was convinced it was because some website made her do two-factor authentication.
And I could not get her to stop telling me about two-factor authentication. No, no has nothing to do with this problem.
She wasn't connected to wifi. Yeah, that knee bone is not connected to that ear joint, which doesn't even exist. Yes, anyway, so we can make use of these exit codes and zero good, anything else bad.
Just different shit, different flavors of bad, but zero good, everything else bad. So how does that affect our script? So our script is a collection of terminal commands.
[24:50] If we use our script within another script or within a terminal command, shouldn't it also have an exit code? Why, yes it should.
And the exit code of your script will be the exit code of the last command that ran.
[25:07] Now, at the moment, since we haven't learned about loops or if statements or anything, the last command to run in our script will be the bottom command of the script.
[25:14] But as your scripts get more complicated, the last command to run could be halfway up your your script if you have an if statement or whatever right that changes where things flow.
[25:22] So your script, its exit code is the exit code of the last command to run. There is a command whose specific job is to end a script with an exit code.
So if something goes wrong you can say exit space and then you type a number. And so you can then decide that if you know my script is only supposed to run on a Wednesday because that's when this business process happens.
And if someone runs this script on a Thursday, I exit with code one. And if someone who's not an admin tries to run this script, I exit with code two, because actually I need to be an admin because otherwise I know that something will fail.
Or you know, you can start to build up these reasons and you would have them in your documentation. So you then say if day of week not equal to Wednesday, exit one.
If user not in group wheel, exit 2. You get the idea.
So by default your script will end with whatever the exit code was of whatever you last ran, which is hopefully a successful exit code. But if you want to end the script, the command to end your script is exit.
And by default you exit 1.
Actually no, by default you exit 0, I think. By default you exit success. But if you want to exit with a specific exit code, then you exit space the number.
And you can enter a script early with a successful exit code. We say exit zero.
[26:50] If your script is supposed to check if something is true and if it's not true, make it true. Well, if you check it's true and it is true, your script is finished successfully.
So you can just at the very top of your script say if this thing exists, exit zero.
And that will show us a successful execution, even if you didn't finish the script.
[27:09] Okay.
[27:11] So it is just basically think of the model as being functions that returns true or false. Only instead of false, you get to have lots of different shades of false.
[27:20] Okay. Now, this is where things get interesting.
[27:26] We're now laying some really important foundation which is so important I want to say it twice. So we're doing it today and then we're going to revisit it at the start of next time's discussion which is all about if statements and loops and stuff because central to both conditional statements and loops are.
[27:47] Basically boolean logic right checking for truthiness of some kind right and if statement evaluates to a question of truthiness. A loop continues until something truth becomes faulty.
The concept of truth and falseness is central to conditions and loops.
And the terminal does not have traditional booleans.
The terminal uses exit codes as its way of telling truthiness. So an if statement on the terminal looks at the result of a command to decide what to do.
And the way it looks at the command is it looks at its exit code. So that means that everything logic-y on the terminal is in exit code logic.
Which means that if you write it down as a traditional truth table it looks wrong to a computer scientist. But if you write it in English it looks correct.
So there are two Boolean operators that are very important. Ampersand ampersand means a logical and and pipe pipe means a logical or.
And so normally in normal computer science world, one and one is one or true and true is true.
In terminal world, zero and zero is zero.
[29:08] But if you say it in English, it's fine. Success is success. Correct. But what is one and one?
[29:17] Well, one and one is error and error is error. So one and one still is one.
[29:24] That is true, but so is two and one and so is 56 and 32. So actually the rest of the truth table becomes really confusing.
So the next entry will be zero and anything greater than one is one because success and any error is error.
I'm going to correct you. Zero and anything greater than zero is one.
[29:47] That is certainly what I tried to say. Yeah, that's not what I said that I was wrong. So one and above, as long as there's a one. And basically if there's any kind of a false in there, an error in there, it turns the combination becomes an error.
Yes. Okay. Exactly. So greater than zero and greater than zero is one. And there's also the OR operator. Right.
Okay. Yeah. There's also the OR operator, which is zero or zero is zero because success or success is success. And then zero or greater than zero is zero because success or error is still success.
Greater than zero or... Wait, wait, wait. Stop. That one hurt your head.
Well, but explain why. Why is zero and one... Zero or?
[30:34] Zero or one. We're on the or table.
[30:38] So true or false is true. Why? So zero, because that's how or works.
Means either of one or the other is successful. Only if that's what you ask it.
[30:57] Okay, but I'm describing the rules for or so the rules for or are by definition. True or false is true.
That is the definition of, of or. Okay. Okay. I forgot that. All right.
[31:10] So that means in terminal speak success or success is success. Success or error is success.
Error or success is success. The only way to get an error is error or error is error.
[31:22] And that is fun in an audio podcast for people. Absolutely. However, this is actually these two tables combined with a technique called lazy
evaluation gives us really powerful, quick to write if statements that don't even involve the word if.
[31:45] Now, bash can do way more and we're going to learn the way more next week, but lazy evaluation is where the... so in order to evaluate a true or false statement, so you use the AND operator,
there's something on one side of the AND and something on the other, and the answer of that whole statement is going to depend on the rules in those two tables. The way Bash does it, and this
is common to a lot of programming languages, is if the first result means that it doesn't matter what the second result is, the outcome is already known.
The second one is not executed and that is guaranteed to you. If I know enough after executing the first one, I will not execute the second one.
I will immediately return the result of the operator and that's called lazy evaluation.
And that is a feature, not a bug.
So would an example be, um, I'm going to use and, and I've already given it a one. I've gotten an exit code of one for the first thing and then it gets to the and it knows that the answer is going to be false.
[32:51] Or error. Yes, precisely, precisely. And therefore it will not do the second. But if I gave it a one and an or, it's like, well, I don't know, I got to execute the second one.
Correct. OK. And the inverse of that is also true. So you can use the two operators to achieve two things. Only run the second command if the first fails. And the opposite thing you often want to do,
only run the second command if the first succeeds. And they're both really powerful things to want to do. Yeah, yeah. So to make it real world, here would be a snippet of a shell script that exits my
script with a 404 error if we fail to restart the Nginx, which is a web server. So the command to restart Nginx is systemctl restart nginx.service, right? Take it from me, that's just how it is in
Linux land. So I say the command. Yes, you have, which is why I picked it. So systemctl restart exit service or exit 404.
[33:53] So the exit 404 will only happen if system CTL is error. Because if system CTL is true, is success. Give me a second to absorb this, see if I can follow what you're saying.
So you've got a command or exit 404. If the first one succeeds, by definition, when it hits the or, it's got to go to a sec.
Well, no.
The opposite. Oh, the opposite. It will, it will only because it's got success or anything. If it succeeds, it knows it succeeded. It doesn't do the next thing.
Correct. But if it fails, then it exits 404. Then you know it's an error and therefore it should execute the 404.
[34:44] Yeah. Or I mean, it doesn't have to be. The thing after the or could be any other statement, right? So maybe it's, you know, logger to send something to syslog or whatever you want to do in response to the error.
But, you know, exit 404 seems like a sensible thing to do because then if your script fails with an error 404, you know, because you wrote it, ah, 404 engine X is cranky.
If it X is with 303, maybe something else is cranky. You know, maybe my sequel is cranky or something, right?
It's up to you to decide what your exit codes mean, but you can use that to then be more intelligent about things. Or you could just use an echo statement. Or you could just say, or echo. It makes sense having followed that truth table with you, but reading it looks funny.
Command or X at 404.
But is it so funny though if you say it out loud, start NGINX or be cranky.
[35:34] It does kind of work in pseudo code right? Yeah, yeah. And then the opposite thing which you also want to do very often,
is do something and only do the second thing if the first one succeeded and the use case for that is test the NGINX config then restart NGINX.
Because NGINX can be running with a broken config because it only checks its config on start.
So it's very common to have a web server hosting, you know, 50 websites for a large university And then you go make a small change because someone wants to change a redirect, forward slash twitter to go somewhere else or whatever.
Well if you made a typo and you just typed systemctl restart nginx you've just taken 50 websites off the air.
That is, that makes people cranky at you. So what you really want to do is a config test followed by the restart, and so nginx minus t will do a config test.
So if you say nginx minus t ampersand ampersand systemctl restart nginx.
Well then the restart only happens if nginx-t succeeds. Right, right, right, right, right, right. So it has to get the exit code of zero because it knows when it hit the ampersand that if it's got a one it's not going to do the second thing.
Oh wow. Correct. That's a good practical example.
[36:50] Yes, and you use that an awful lot because it's so much easier to just type ampersand ampersand or pipe pipe than it is to do a whole if statement.
So you will see a lot of this kind of, you know, do something or be cranky or do something and follow through.
[37:06] And that's basically the hat. That's how you do it in terminal land. But of course you could do more with if else an elif, which is the terminal version of else if.
But as we learn in the next installment, the terminal is very verbose about its if statements because it's not a statement.
It's actually a whole bunch of commands. So it takes one, two, it takes at least three commands to do an if statement on the terminal.
[37:35] And it could be many more. Whereas this is just a one liner. So this is why shell script geeks love these little ampersands and oars because they're so much easier than if.
But if is fine, as we learn about next time. It does work and it's very powerful, but it's a bit verbose. It's a lot of typing.
So yeah, anyway, that's where we're going. So at this stage we know how to write a script, we know how to put some variables in it, we know how to take input from the user in the most basic way, so as arguments just asking the user.
We know how to return exit codes, we even know how to use those exit codes for some basic logic, which means we're now ready to move on to what I think is the raison d'etre for this entire little mini-series.
The ability to control the flow of things inside the shell script.
In other words, if something is true, do something else. and obviously keep doing this.
[38:29] For this many times or until this thing happens or until this thing doesn't happen but basically the ability to branch and to loop. Can that that is what gives you shell scripts great power and so that will be the entire focus of the next assignment is that you know branching and looping
And that will set us up perfectly to finish our exploration by looking at the plumbing,
as I call it.
In other words, piping stuff into your script and making sure that your script plays nicely with people taking its output as a pipe into themselves.
So basically, can I sit in the middle of a pipe? If you want to read ahead on doing the terminal plumbing, Bart did cover this in installment 15 of the Taming the Terminal series.
And there's a link in the show notes, of course, to that.
[39:14] Yes, so that will explain the plumbing but of course what we what we're going to learn is how to play nice How do we be a good elbow joint?
Is I guess.
[39:27] Yes, exactly All right how to be a part of the plumbing instead of just using it to connect together other people's commands All right My script should be able to sit into that structure and play nice,
With all the other terminal commands and scripts and things and so that's that is the final piece and then Then we have all of the tools we need to automate, because the whole reason we care about this is to automate our build process in our code.
Because now that we're starting to use lots of different tools to make complicated code that needs to be built into a final version and stuff, there's actually quite a few commands to go from source code to working product.
[40:05] And I'm a lazy sod. I'm also a typo prone sod. So I need to script this stuff for my own sanity and for my own consistency. And so that's why, that's why we're doing this.
And so that's why this is only a short dip into shell scripting instead of, you know, we could spend months.
Actually, no, us being us, we could spend years, but we're not going to.
So that's, that is where we stand. I really do like learning this. And this is the kind of thing, had you taught me this four years ago, I would have said, I don't have anything to automate.
And it's been interesting watching the number of things that I've started to think, hey, I could do that faster. I could do that without ever typing it the first time.
And now I'm in the mode where when I start to work on something, I'm like, hmm, bet I'm gonna do that twice. Let me automate that before I even start.
Again, because the error code is always one when I'm doing it by hand.
[41:05] Right, and it's a good way to think about things, right? If I can express what I want to do as a piece of code.
Then I have to think about it logically for a start. So I'm more likely to get it right. But also I now have it versionable. So the process has become something in version control.
[41:23] That's actually very powerful because you've now captured process. So particularly on a shared team, capturing process is actually very powerful. Yeah, yeah.
Well, this is fun. And I'm glad for my first show back after a vacation that you went easy on us here.
Well, I went to, believe it or not, right, this show was really fun to record and it wasn't very long, but this is the most difficult one I've written in as long as I can remember.
Really?
Because finding a path through what I want to do that doesn't involve me saying, now ignore this line, we'll learn about it next week.
Okay. So hard to find a path. So you had to dance your way around, huh? Okay.
I had to tiptoe my way around and it just was not coming together. I you almost got a panic tech message from me about eight hours ago, but then just in time everything fell into place.
So we did make it in the end. But anyway, yes, let's stop rambling on. Let's keep it a short show. And remember, folks, very important until next time.
Happy computing.
[42:26] If you learn as much from Bart each week as I do, I'd like you to go over to let's dash talk dot IE and press one of the buttons over there to help support him.
He does 98% of the work here, I'm just the stooge that listens to him and asks the dumb questions.
If you go over to letstashtalk.ie, you can support him on Patreon, you can donate via PayPal, or you can use one of his referral links.
I really hope you'll go over and help him out. In the meantime, you can contact me at podfeed or check out all of the shows we do over there over at podfeed.com.
Thanks for listening and stay subscribed!