 I wanna talk about something that really separates elegantly written Bash and shell scripts from not so elegantly written ones. Here's a rule of thumb that I've mentioned before on my channel, but I wanna explain it. And that is, when you're writing a shell script, 95% of the time, don't use if statements. That sounds like a weird thing. That's a basic thing in programming. If this is true, do that or do that, if it isn't. That's a very common thing. But when you're writing shell scripts, there are logical operators that exist that make it mostly unnecessary to do that, in most of the times, not all the times. There are some times where you do wanna use if statements, but let me explain. So just in general, here are the logical operators I'm talking about, and you've probably seen them if you write written scripts, but knowing how to use these will make the difference. It will make your scripts much more elegant. You'll be able to remove some ugly if statement and replace it with one line, okay? Here's one, and, and. Here's another, pipe, pipe, or, or. Here's another, semicolon. And here's the last one, single and. What is the difference between all of these? You probably see these every once in a while. Let's talk about the difference, and then we'll show you, I will show you how you can make scripts a little more elegant. It's just good looking. It's very shell-like. It's very bash-like to use these properly. Okay, so here's a basic example. Let's talk about the most basic one is probably semicolon. Semicolon means run a command, and then you provide a semicolon, and then it will run the command afterwards. So let's say, here's an example. Echo, hello there, okay? So if we, what we can do with semicolon is we can chain commands together. So let's say we have echo hello there and echo general Kenobi, okay? So we have these two commands, and if I put them together with semicolon, it will execute both of them. It will execute the first one and then the second, all right? That's what semicolon does, and it's pretty promiscuous. It's pretty much always gonna work. You know, it's not gonna change its mind halfway through like the other ones will, which actually that's the magic of the other ones, but just to be clear, semicolon is basically the same thing as having a new line. So if in a shell script we had something like this, echo blah, blah, blah, and echo blah, blah, blah, this could be rewritten as the following. It could be rewritten as that. You could get rid of the new line and put a semicolon between them. That's basically the same thing, okay? But let's talk about the other logical operators because that's where the magic happens. So first off, and, and, if you replace semicolon with and, and, it's gonna look like it did exactly the same thing. It did actually do the same thing, but the logic behind it is a little different. And, and is picky. And, and only runs the second command if the first command succeeded. Only in that circumstance if the first command succeeded. So here's an example. Instead of echoing something, let's try and cat a file because that's something that can go wrong. For example, I can cat my Z profile and it'll print out that file. So that program, that command ran successfully. But if I try and cat out my bash profile, well I don't have a bash profile, that command failed. So here's the difference between semicolon and and and. Well, if I say let's go back to catting out my Z profile, again I have a Z profile. And then I say echo, this is my profile, okay? So I can print that out or cat that out. And then if I have a semicolon, it will show this little thing at the end, this is my profile, it ran that command as well. And I can just in the same way as I did with those two echo commands, I can do the same thing with and and. It will run both of the commands. But the difference is, what if, here's the case that's different. What if instead of trying to cat out my Z profile, I cat out my bash profile, which again does not exist. If I do that, since we're using semicolon, I try and cat this out, it doesn't work, it fails. But semicolon, it's just gonna run the command that's next. So it's gonna still print out this is my profile. I don't really want that to do that. So what I'm gonna do is I'm gonna replace it with and and. And the difference here is that it's gonna try and cat out bash profile. That command fails and and and only runs. It will only run the second command if the first command succeeded. So in this case, it will not print out this is my profile. And this is probably the preferred way to do it because we only really want that label if the profile prints out, okay? So that's what and and is for. So it runs only if the first command was successful, whereas semicolon runs all the time. Now pipe pipe or or is the opposite of and and. It only, so for example, if you have this, let's say, well, I'll rewrite this. Let's say I rewrite this. Cat out bash profile or print out file does, doesn't exist. Okay. Now in this case, what that did does is it tries to cat out the bash profile and when we get to or or pipe pipe, it says, okay, I'm gonna run the second command only if the first command did not succeed. In this case, it didn't succeed. So it printed out the second. It did the second command file does not exist, right? But if we switch this file to let's say Z profile, which does exist. So this command will succeed. Now you'll notice that the second command did not run. That's because pipe only runs the second command if the first one failed, okay? So that is the difference between these three. Now you might already in your brain, you might already be thinking, okay, I can probably replace this or that if statement with this and that's true. I'll show you that in a second. But just to be clear, there's one other logical operator and that is single and, which is utterly different from and and. What this is, just to be clear, let's have a case. Let's say the command sleep five, which by default will wait for five seconds and then continue, you can do whatever else. So we can chain that together with an echo command. So all done. So what this is gonna do, it's gonna wait five seconds, then it's gonna echo all done. Now the difference between these operators and and or these three on the top is that all three of these wait for the first command to be done. Then it runs the second commander, runs it if it failed or succeeded. The difference between single and is that single and will start the first command and then it'll just start the second command. Doesn't matter if the first command's done or not. So if we run this, you'll see that all done actually prints out immediately once this command starts and then a couple of seconds later, you'll get this message that says that the sleep command is done. Now to be clear, this should be the process number of the first command that it temporarily abandoned. Which you can do stuff with that, but that's another issue. Okay, so let's talk about a real life implementation of this. So I'm gonna write an example shell script and here's the implementation I wanna do. Let's say for example, let's replace an if statement that we might be tempted to use with one of these. Let's say, so there's something on, most systems will have what's called an editor variable defined. So in this case, my editor's NeoVim. So an editor variable, usually you'll have them on systems. They just define what your favorite text editor is that a program might open up your favorite text editor to do something. But let's say in many scripts, there are some systems where editor variables are not defined. So you need to basically check if that variable is assigned and if it's not, you might wanna assign it in the script. Okay, so here's how you would write something in elegantly with a if statement. You might be tempted to do something like this. If, we'll do it very in elegantly, if the browser is equal to nothing, okay, then do the following set, or not browser, editor, sorry. I don't know why I'm thinking of browser. Sometimes people use the browser variable as well. So if the editor is equal to nothing, then set the editor equal to, I'll say nano is the default editor because I don't know, I guess people can usually use that. And then I'll close my if statements. So I will say this is ugly. Bash's syntax is very ugly when you do this because look, you have this weird thing in brackets. You have this semicolon then, you'll always forget all this kind of stuff. It's just a big annoyance. And of course it's three lines. You could actually put it on the same line with some semicolons and stuff, but this is how you typically write it. There's a much better way to do this. Actually, well, let's make sure that this script will work first off. So I'm gonna run this script. As I said, my default editor is in Vim and it's gonna print out in Vim because what I have this doing is checking to see if there's no editor variable and whatever it ends up as, we're gonna print it out. But let's say I unset my variable, unset example, unset editor. So let's say I unset my editor variable. So now I have no editor and I run this command again, example, and it is now gonna print out nano. Again, what it did is it checked to see, oh look, this editor variable is equal to zero, so assign it to nano, okay? Otherwise it would have run in Vim, okay? Now, how can we more efficiently write this just with the error code things? Here's what you can do. Well, first off, actually aside from error codes, this is a lot of times people will do this if a variable is equal to some empty string or something. A more elegant way of writing this is with the Z tag. So if you just write Z editor, then nano. So that'll be, the dash Z basically means if this is equal to nothing, right? Technically, there's a difference between a variable assigned to an empty string and an unassigned variable, but we won't talk about that here. But anyway, so in this case, basically this is exactly the same as this. So that's one optimization, but here's another thing. Actually, I'll just show you what it looks like and you can figure it out yourself. So Z editor, that is if editor is equal to zero. This is implicitly already an if statement. You don't actually need if or then or else or LF or the end of the if statement. You can just say this, editor equals nano, okay? These lines, this if statement, that can be more tersely stated as just a single line. That is, if there's no editor variable, assign it to nano. And this is gonna work exactly the same way, okay? Or if we have, if we have a, our editor is equal to in VIM, we can run this L and look, it's gonna be in VIM. Or if our editor is equal to, I don't know, normal VIM, it's still gonna work, right? So basically most if statements can be replaced with just one of these things. If you actually check, just check a variable and do this. Or for any command you can put here and then just have and, and, or, or after it, and, or, or pipe, pipe after it and check to see or do whatever you're supposed to do, right? So that's a more elegant way of doing it. So here's another, I will give you one minor example, sort of a, not a brain teaser, but something to think about. Now I wanna talk about one more example. I'm not gonna write out, write out a whole example for you, but one that came to my mind that's in one of my scripts. Here is my mutt wizard script. And just as an example, here's a real life implementation that actually makes, makes using error exit codes and these sort of logical operators much more efficient than the alternative. Here for example, this is my mutt wizard where I'm getting, I'm having the user input information about their email account and then we try to connect to it and finalize it and do some things. And if any, if anywhere in that process it fails, I want it to delete the account, the account information so it doesn't mess things up, okay? So that's one real life implementation. Now you don't need to know what all these functions are but I've defined a bunch of functions in this script. For example, I ask the type. Oh, what type of email do you have? What is the info? Ask info is asked for that. Then we try to connect to it, blah, blah, blah. Now the important thing is, what I want is I want it to follow. I want it to do all these commands. It does ask type. It asks for the type and we have and and here meaning only if that succeeds do we go to the next one. Then we have and and again here. Only if these two have succeeded do we go to the next one. And then we have and and here. Only if these two succeed do we go to the next one. And if there's an error code think about it this way. Let's think about it linearly. Let's say there's an error in this function, okay? What it's gonna do is it's gonna this bash or whatever your interpreter is is gonna get to this next logical operator and it says, ah, there was an error code before. This is an and and therefore I'm not gonna run this command and then it's gonna get here and it's gonna say the same thing, okay? The last command failed so I'm not gonna run this. Then it's gonna get to this the pipe pipe the or statement and it says, ah, yes, the last command that ran failed so I'm going to run this delete function. So this line here is an example of a very efficiently written series of functions where instead of doing something stupid like, oh, check if this command run ran successfully and then check this it's results and stuff like that. No, now screw that, just use exit codes. Just use these logical operators and you don't have to have anything too fancy. It's just a bunch of commands together. It just works very well. Anyway, so that's about it. That's enough for this video. You know, I said a bit ago I wanted to do shorter videos but I realized that I've just been going so hard for these past couple of ones that they take a little longer than I intended but anyway, that's about it. I'll see you guys next time.