Bash Commands and Scripting - From Beginner to Expert | Chris Frewin | Skillshare

Playback Speed

  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x

Bash Commands and Scripting - From Beginner to Expert

teacher avatar Chris Frewin, Full Stack Software Engineer

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

24 Lessons (3h 7m)
    • 1. Introduction

    • 2. Nomenclature, UNIX, and Shells Overview

    • 3. The Basics of a Terminal Parts of a Terminal and How to Interact With One

    • 4. Bash Commands Part 1 - Navigation and Interaction Commands pwd, ls, cd, open, clear, cat

    • 5. Bash Commands Part 2 - Data Modification and Editing cp, mv, touch, mkdir, nano, rm

    • 6. Bash Commands Part 3 - Flags and man

    • 7. Bash Commands Part 4 - Data Translation and Using the man With sed

    • 8. I/O In Bash - Reading, Writing, and Piping

    • 9. Bash Commands Part 5 - More Advanced Navigation and Stringing Commands Together cd, open

    • 10. Creating Aliases and The Bash Profile

    • 11. Creating Functions in Bash

    • 12. Create Your Own Bash Profile

    • 13. Bash Commands Part 6 - awk or gawk

    • 14. Bash Commands Part 7 - wget, curl, and traceroute

    • 15. Bash Commands Part 8 - tree, free, ifconfig, memory pressure

    • 16. Logical Operators - if, else, and case

    • 17. Error Handling in Bash

    • 18. All the Loops - Types of For Loops and While Loops

    • 19. Environment Variables and the export Command

    • 20. Bash Commands Part 9 - which and the --version flag

    • 21. Bash Commands Part 10 - lsof, process IDs, kill, killall

    • 22. Bash Commands Part 11 - chmod

    • 23. BONUS: Change and Style Your Bash Prompt

    • 24. Outro

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels
  • Beg/Int level
  • Int/Adv level

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.





About This Class

NOTE: The course GitHub repository is here:

Note that each branch corresponds with what was done in that lesson. (For lessons 3 to 23)

This course is about Bash commands and scripting. Knowing basic Bash commands and some Bash scripting techniques are essential skills for developers of any type to learn - and can help with so many day-to-day tasks. In this course, we'll start at the most basic level, opening up a terminal application, examining exactly what parts of a terminal there are, and how to interacting with it using only your keyboard. From there, we'll start learning more and more commands, and we'll see and use ever-more complex bash scripting techniques.

This course is great for beginners: I believe If you practice enough with each lesson along the way, YOU can become a bash scripting expert! This course is also suitable for intermediate or long-time users of bash: you might find it a refreshing review, and maybe you'll even learn something new, or perhaps re-learn something you've forgotten!

I had a lot of nostalgia recording this course, thinking back many times to when I first learned bash scripting in a course during my master's program years ago. My goal with this course was to make the lessons even more efficient and succinct than those in that university course, and especially to add additional lessons based on what I have learned and used the most in bash over the years as a full stack software engineer.

I already had a few people reach out to me asking about the bash commands and scripting techniques I use in some of my other courses. That prompted me to make this course - from what I've heard, there's just not enough resources out there that cover all aspects of bash and bash scripting. This course is my solution to that! I hope you'll join me in this course, titled, "Bash Commands and Scripting - From Beginner to Expert"!

In the first lesson, I'll provide a small background presentation on the nomenclature: various shells that exist, UNIX and UNIX-like systems, and where Bash comes in. In the second lesson, we'll open we're going to start with the absolute basics, of how to open up a shell, and how to interact with it on the most basic level, just using the keyboard and how to write a basic command. Through each subsequent lesson then move on into ever more complex examples, learning how to create what are known as aliases in bash, then onto functions, logical operators, loops, and more!

Meet Your Teacher

Teacher Profile Image

Chris Frewin

Full Stack Software Engineer


Hi everyone!

I've been a professional full stack software engineer for 7+ years, and I've been programming for many more. In 2014, I earned two separate degrees from Clarkson University: Mechanical Engineering and Physics. I continued at Cornell for my M.S. Degree in Mechanical Engineering. My thesis at Cornell was a technical software project where I first learned Bash and used a unique stack of Perl and Fortran, producing a publication in the scientific journal Combustion and Flame: "A novel atom tracking algorithm for the analysis of complex chemical kinetic networks".

After opening up my first terminal while at Cornell, I fell in love with software engineering and have since learned a variety of frameworks, databases, languages, and design patterns, including TypeScrip... See full profile

Class Ratings

Expectations Met?
  • Exceeded!
  • Yes
  • Somewhat
  • Not really
Reviews Archive

In October 2018, we updated our review system to improve the way we collect feedback. Below are the reviews written before that update.

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.


1. Introduction: This course is about bash commands in scripting. The bash language and Bash scripting are essential skills that any developer should have. And that can save you so much time in your day to day tasks. In this course, we'll start at the most basic level, opening up a terminal application, looking at what parts of the terminal they are and how to interact with the terminal using only a keyboard. From there. And each lesson, we'll learn more and more commands in ever more complex bash scripting techniques. This course is great for beginners. I believe if you practice enough with each lesson along the way, you can become a bash scripting expert. This course is also suitable for intermediate or long time users of bash. You might find it a refresher and maybe you'll even learn something new or perhaps relearned something you've forgotten. I had a lot of nostalgia of recording this course, thinking back many times too, when I first learn bash scripting in a course during my master's program years ago. My goal with this course was to make the lessons even more efficient, insisting than those in that university course. And more importantly, add additional lessons based on what I've learned and use the most in Bash over the years, I've been a full-stack software engineer. I've already had some people reach out to me about the bash commands in scripting techniques I've used in some of my other courses that prompted me to make this course. Apparently, there just aren't enough resources out there which cover all aspects of bash. Bash scripting. This course is my solution to that problem. I hope you'll join me in my course title, bash scripting from beginner to expert. 2. Nomenclature, UNIX, and Shells Overview: So before we actually open up a terminal, I just quickly want to go over the nomenclature surrounding bash and shells and unix. And so I've put together this very short presentation. I've just titled it Unix and shells and born, oh my Z, SH. And that's a play on words with the OMICS H, if any of you know about the ASH environment or community, that's kind of their tagline is the OMICS h, right? And this is for this course, bash commands and scripting from beginner to expert. So the first part here, I have put together a flowchart, kind of describing how Unix developed and where shells came from, and then where bash comes in. Then at the end of this presentation, I have a table with all the features compared between the various shell languages. So let's get into the flow chart. And so the first concept here is shell. And the shell is a computer program which exposes an operating system services to a human user or other program. And so it's both a command and scripting language. Then we have unix or Unix-like. And these are operating systems that can form 2 or nearly conform to any version of the Single unix Specification, which was developed at Bell Labs in the 1970s. And so the first shell for Unix systems was the Thompson shell that was developed by Ken Thompson also at Bell Labs between 1971 and 1975. The shell that came after that was the Bourne shell and that binary is typically denoted with SH. This show was developed by Stephan born at Bell Labs in 1989. And actually this SH binary is still found on most Unix or Unix-like systems today. It's similar to bash, but has a smaller feature set. Then dash. Now from this Bourne shell, there were a bunch of shells that kind of followed suit. So I'll go over a few of them. One of them was the OEM quest shell, which is ASH. And this was developed by Kenneth arm twist in the late 1980s. And today it's the shell of FreeBSD and Net BSD. There was also the Korn shell or TSH, and that was developed by David Corn at Bell Labs in the late 1980s. Then we have the bourne again shell or what this course On bash. This was developed by Bryan Fox for the GNU project in 1989, and it's the standard shell on most Linux systems. However, in years of late that has started to change slightly. There's nowadays dash ASH, there's also see TSH, TSH and many more. So when I said in years of late that it's beginning to change from Bash. We've seen in 2020 that Mac has officially shifted to ASH. And nowadays on some Linux systems, dash is the shell language of choice. And really the only difference between dash TSH in Bash are a few additional features that the new shells have above bash. But 99 percent of the commands and behavior among all those shells is very similar, if not identical. And so here I've left a detailed table comparing some of the most popular shells and what available functionalities they have. This was actually from a Stack Overflow post, which I've put in the bottom there. And even from there, I believe it came from the GNU project or a similar website. But I'll leave this presentation in the show notes. So you'll have this table and these links to all the sources. And note that it is two pages and you can look into those details. So now that we've got a broad overview of what Unix is, what a shell is, and where bash fits into the family of shells. We can get started in the next lesson by opening up our first terminal and looking at a broad overview of how to actually use and navigate in the terminal. 3. The Basics of a Terminal Parts of a Terminal and How to Interact With One: The last lesson, we saw a review of various shells that have been created throughout the years. And we pick Bash as it is still the default on many Unix and Unix-like systems. So I'm going to open up the terminal application here on my Mac using the spotlight search. And I'm just going to do Command plus a few times just to make the font bigger. So you guys can see within Linux operating systems like 12, you can find the terminal program even in the launch bar, I think nowadays it ships as a default in the launch bar. Other unix and Unix-like operating systems like min OS, Red Hat, and so on. You'll need to find out how to do it. But it shouldn't be too hard to find. And if you're using SSH on a remote server, well, you're already in a terminal and likely it is Bash or a very similar shell. So for now, we can ignore this warning message. I'll mention that in the next lesson. For now, I just want to go over a very high level overview of what a terminal typically looks like and how you can interact with it. So the first thing I want to highlight here is this part of the terminal. This is known as the prompt. Typically for most shells, the default for this prompt is the username, the at sign, and then the machine name. So here on this computer, my username is Chris, and the machine name is Chris MacBook Pro. This little thing here will show you the current directory you're in. And the squiggle is the root directory in the Bash language. And I know we haven't learned the command yet, but just to show that this is dynamic, at least here in this environment, I'm going to change it into the project directory. And we see that the prompt has changed to show the project's path. So again, that's what this prompt is here, default in Bash. But we'll even see in a later course how we can customize this prompt with various colors or even make it something like a Smiley or even add emojis. So this part is the prompt. This part here is the only place you can type in this whole window. It's a single line, and it's simply the input. And so you can type characters for as far as you want. They'll carry over into the next page. And you submit commands with the Enter key. So I'll do that now. And we see that bash isn't very dangerous unless you're typing some dangerous commands. But as a beginner, you wouldn't know about there isn't really any risk in just typing nonsense bash, we'll just ignore it. It doesn't know what commands you're giving it. And so while writing commands, if there's a long command and you've made an error, you can use the left and right keys to navigate on that command. If you go to the right, you can't go beyond the last character. And if you're too lazy to go back and edit or you want to cancel the command for any reason, you can just press Control C. And while it looks like I've pressed Enter, that command has actually not been entered. So you can always press control C to cancel whatever you're doing at that time. Another important feature of the terminal application is that you can use the up and down arrows to look through your previously entered commands. So even if they're not valid commands, they will show up in this history. And you start by pressing up. So if I press down right now, there's nothing in the history. I haven't entered any new command. I can't go down. So you always go through the history by pressing up. And so we see the command I entered here. And if I press up again, it would be this one. And note that this command does not show up in the history because here I entered Control C, So that command wasn't actually submitted, and therefore, it's not in our history. But anyway, this way of navigating through old commands can sometimes be useful, especially if you're calling the same command very often. Or if you've forgotten a command, you can go up a little bit and find it. So that was a brief high level overview of what a typical terminal application looks like. We saw that this part here is called the prompt. We can enter commands here on this single line. We can navigate through an existing command that we're writing using the left and right arrows. And we can also look through previous commands with the up arrow. We also saw that if you want to cancel the input of a command or simply just start over to start typing a new command. You can always press control C at anytime, and that will give you a fresh, clean input to start writing in. So with that high level overview done in the next lesson, we'll start learning our very first real bash commands. 4. Bash Commands Part 1 - Navigation and Interaction Commands pwd, ls, cd, open, clear, cat: So in the last lesson, we saw a review of various shells that have been created throughout the years. And we pick Bash as it is still the default on many Unix and Unix like systems. And it'll probably be around for years into the future. So I'm going to open up the terminal app here on my Mac via spotlight. And just increase the font a little bit easier for you guys to read. And right away, we get this little warning. The default interactive shell is now zs H. And you can switch to that with this command. So 99% of what we do in this course will be compatible with z, SH, or perhaps even all of it. So if you want to follow along with the default shell for Mac nowadays, you can go ahead and do that. But because this course is going to be specifically about Bash as a shell, I have already switched to using Bash as my shell. And so that can be accomplished if you're in Mac with the same command, but instead of the z SH binary, you switch to the bash binary, so that's bin bash. And you'll need to enter your password. And like I said, I've already switched to bash, so no changes were made. So for now we're gonna go through a handful of very common bash commands. In this lesson, w1 is mostly used for navigation and listing things. So remember from the last lesson the definition of a shell is just a command and scripting language which provides access into the operating system itself. So anything we're able to do in the GUI, for example, here on Mac, in the Finder application where we can view files and folders, we should be able to do that in some form here in the shell. Another thing I want to mention is that Bash syntax is quite short and oftentimes fairly easy to remember. They are not too many long command names or keywords that you need to remember. But even when that's the case, we'll see how we can create some custom commands in future lessons to kind of get around that and remember commands for ourselves. So finally, the very first command we're going to learn here in Bash is PWD, which stands for print working directory. So I'll issue that now. And this command does exactly that. It prints the current directory that we're in. Since I'm on a Mac and in a freshly open terminal, the default directory here is my users root folder. So users slash Chris, which is my username on this machine. If you're on a Linux system, you might find yourself in slash route or perhaps slash whatever your username is depending on how you're logged in or the OS you're using. So we're in this default directory. But let's see how we can list the folders and files in this directory. Command is ls, which stands for list. All this command does is list the files and folders in a directory. So in my root here on my Mac, I've got the typical MAC folders to my desktop, documents, downloads, movies, music, and so on. Now, just like in Finder, Let's say we want to move into one of these directories. And for right now let's move into projects here, which is where I have the folder to the course repository where I'll keep all the commands and notes for each lesson. And so the command and bash is CD, which stands for change directory. And we pass in the directory that we want to change too. So we can do that now. And now we can see in the prompt here that we are currently in the projects directory. If you don't have a prompt like this, we can use a command we've already learned, which is the present working directory to check. And we see now that we're in the Projects folder. So I've already forgotten what I called this lesson repository. So let's use ls and check what we've got in here. And we can scroll through. I believed I called it yes, bash commands and scripting course. So we're going to cd into there too. And now the other nice feature with bash is that it has tab complete. So if there's no other folders that start with the the bash dash C, which I don't have. If you press Tab, it'll autocomplete for you and finish the command, and then you can just press Enter. Now let's also check what I have in here. Nothing more right now then a shell script file, which we'll learn about in the coming lessons. So one thing you might notice is that this running log of command output is rather annoying and can get cluttered and it's hard to read or see what you're doing. So the fourth command that we'll learn for this lesson is called clear. And of course that's simply clears whatever output has been listed in the terminal. So I'll enter that now. And we see that were brought up to a nice clean terminal again. And additionally, we haven't really lost that output. Clear just clears what you're currently seeing in the terminal app. So you can still go back and see previous commands. Clear, just clears what you see in the visible part of the window. And now we had this lesson 3 shell file. And so another command will learn in this lesson is called Open. And open, we'll just use whatever your operating system's default is based on that file or that file extension. So actually I'm not even sure what it is for Mac. I'm going to give it a shot here. And I'm using tab completion, since that's the only file with that name here. And we see that the default turns out to be Xcode. Typically I would open this in Visual Studio code or a different code editor. But it seems that the default in Mac for shell scripts is Xcode. And so this file is empty. But for now, I want to write to illustrate the next and final command that we'll learn for this lesson. And so I'm just going to write some comments in this file. And then just save that and close it out. So let's list again. Nothing's changed here. We see our file. But without actually opening a GUI or program like we did with the open command, we can also view the contents of this shell file or any file really with the command cat. So that is CAT less than three SH. And it prints immediately the contents of this file, which is nothing more than is comments, comments, comments, line. And so that's it for this initial command introduction lesson, we learned six bash commands, PWD, which is present working directory ls, which stands for list, CD, which stands for change directory open, which opens the file clear, which clears the terminal, and cat, which lists the contents of the file that you pass to it. And so the commands in this lesson focused mostly on navigating and interacting with files. But in the next lesson, we'll get into doing some simple data modification and editing using Bash. 5. Bash Commands Part 2 - Data Modification and Editing cp, mv, touch, mkdir, nano, rm: In the last lesson, we learned some initial bash commands which were focused on navigating and interacting with files and folders. In this lesson, we're going to move on to a bit of data modification and editing of those files and folders. So I'm already here on the lesson for branch, and we'll use the ls command to list what I have in here already. And it looks like we have a file one dot TXT will use the cat command, which we also wanted to concatenate out contents of that. Okay, and it just says hello, I'm file one dot TXT. And so the first command in this lesson that we're going to learn is copy. And that's done with command cp. And so if we want to copy this file one dot TXT, for example, into file two dot TXT. We simply write CPP file one tab for auto-complete. And then the target file to copy too. So we'll just name it file.txt to keep it simple and press Enter. Now if we list out the files, now, we see that we have file two. And if we cut that out, we see that the contents are identical to the file one. So that's how to copy files. But how do we actually create files? One way to create files in the shell is with the touch command. And so we're going to make a file three. So all we do is touch and the filename with the extension. We will ls again. And we see that our file has been created. Let's cut out what is in 53. And since we've just created it with touch, There's no contents in a file, so that's fine. So we know how to copy files, create files. But what about folders? Well, you can do that as well in Bash. To create a folder, you can use the make dir command or MK dir command. So I'm going to kind of following the pattern of this lesson. I'm going to call it the folder one. Then you simply press Enter. Again. We'll list out just to make sure that we're actually creating these files and folders. And we see it there. And I have in my highlighting and usually built into bash, is that folder show up a different color than files. So this is a green color. Now as opposed to copying files, we can also move files around in Bash. And that is with the MV command, which stands for move. And so I will move that file three into the folder 1 folder using the move command. And so similar to the copy command, move is used by passing the target file. And then the second Parameter is the destination. So we'll keep the filename. And then we can list out again. We expect file three to be gone. It is. And we can use the CD command from the previous lesson to go into folder one, and we'll list out its contents. And we see that file three has been moved into folder one. And it also should still be an empty file because we haven't put anything in it. Now, let's say we actually want to edit and change the contents of file three since it's empty. To open up an inch Shell editor, we can use the editor which is known as nano. And so we can do that simply by writing nano. And the target file, which for us right now is 53. And I'm just going to write hello. I'm file three. And we see here to exit, that's Control X. So onto that into my keyboard Control X. And the nano will ask us, Do you want to save this modified buffer? And we press Y for yes. It also asked the file name to write. We want to keep the original and so we just press Enter. And it should be saved. Now to check that it actually changed the contents. Let's cut that out. And great, hello, I'm file three dot TXT. So far we've learned how to copy files, move files, create files, create folders, and edit files. So you might be asking, how do we delete files and folders? That can be done with the remove command, which is RM. But before I even typed that, I want to mention how to use RM in Bash. I can't stress enough how careful you have to be with RM. Rm is not like dragging some files into the trash can. When they're removed with RM, they are gone. Okay. So with that said, we're going to remove file three. And so that's simply with RM. By all three dot TXT and enter. We can list out the files in here to make sure it's really gone. And yes, it's gone. And no, you won't find it in the trash can. You won't find it in temp, you won't find it in any directory. It is removed, it is gone. So be careful with this powerful command. So in this lesson, we've moved on to more manipulation commands. We learned how to copy files, move files, create files, create folders, edit files, and delete files. In the next lesson, we'll look at a bit more complex manipulation that is only changing specific parts or specific contents of files. 6. Bash Commands Part 3 - Flags and man : So far we've explored a variety of bash commands. It's getting pretty hard to remember all of them, right? Well, I've got good news and bad news. The bad news is that there's a further level of customization and configuration that comes with each batch command that we've already covered. Those are known as command flags, where you can configure how that command behaves. The good news is bashes pretty flexible with these customizations. And there's also a detailed official manual which catalogs all of the possible flags to choose from and what effect they have. And so command is man. And in this case with men, you have to pass in the command you want to read the manual for. So as a first example, let's take a look at Ls and see what the manual has to say about one of the very first commands that we learned. And so it pops up right here in the terminal, gives us a name, synopsis, and a description to the name which we already covered, ls list directory contents. The synopsis is where you'll find all the flags. And because ls is such a simple command, it has many, many possible flags to pass in. And the way you pass flags, as it's already shown here in the manual, is with a dash. And so there's a variety of flags which you can pass two Ls. The few that we'll pass in are this h, lowercase h, which will give us the file size. And the H is typically for a human-readable. And when we combine it with L and with K, will get the file size in kilobytes. And also a useful one is the dot entries. And typically in Unix systems, dotted entries are actually hidden files. So you can back out of the manual with Q. And so our standard LS will show us some files. But let's look at that dash a, which shows those hidden files. Issuing Ls with the dash a flag, yields a few interesting things. The first is these dot and dot-dot locations, which we'll get into in a future lesson. But these essentially stand for the current location. And dot dot is the previous location, which would be the Projects folder. But we'll get to that in a future lesson. We also see the hidden git folder, which is the repository data for this folder, since we're in this course repository. And for this course, I also made a hidden file just by prepending the dot into the filename. So again, issuing the normal ls won't show those hidden files. That's its default behavior. But if you pass that, A flag. We can see all those hidden files. You may have also noticed that when I issue ls alone, the files are listed horizontally with another flag. We can make that into a list, which is the dash l flag. And returning to the good news side of the story, with bash, these flags are extremely flexible. We can combine flags, so we can do dash L and a, and we'll get both behaviors. We'll see the hidden files, and also we'll see them in a vertical line. So let's issue that. But it gets even easier. Bash doesn't care which order. You pass these flags. And you can even pass them as separate flags and all produce the same output. With some commands, the order of flags does matter. But that's usually the exception to the rule. And you can read in a manual for all commands for when the flag ordering actually matters. But typically it's not the case. And so let's also look at men for one of the commands we learned last lesson which was copy. And one of the nice flags with copy is the dash R command. And I was intentionally leaving all that out in the previous lesson just to keep it simple. But we can see with dash r, For example, we can copy an entire directory and the entire subtree. So if we had some files in a folder, we can copy that entire folder with those files in it to a new location. For example. The other nice thing about the manual is that the flags are listed in alphabetical order for the easy to find. And in some cases, you may even find examples near the bottom of the manual entry. So again, we'll press Q to get out. And just another tip of the hat to bash to show how flexible it is. Yes, we can even get the manual entry of the manual itself, which shows us what it does, format and display the online manual pages. So in this lesson, we learned about the Bash manual and we first looked at Ls and all the various flags that it has, focusing on the dash L and a commands. And we saw that bashes rather flexible. It doesn't really care how we provide the flags, in what format or in what order. It typically has the expected effect of combining both of them or as many flags as we pass. We also looked into the manual entry for the copy command and manual itself. So now that we've taken an initial look at passing flags to commands, we can really get into a lot more complex and granular effects that we can do, manipulating data, files and folders in the shell. And so we'll get started with that in the next lesson. 7. Bash Commands Part 4 - Data Translation and Using the man With sed : In the last lesson, we learned about the manual, which could be accessed via the man command used with any command of choice. And we learned about the concept of flags, which you can use to configure or change the behavior of many of the given commands in Bash. And so in this lesson, we're going to look at a more real-world application using the manual, where we'll create a very granular data modification using Bash. And so let's look at what files I've prepared for this lesson. We see we have file one. So let's look at what's in there. And we just have a sentence that says My favorite color is blue. So let's imagine a case where for some reason you'd want to change blue to pink. This would be relatable in a case where you need to change a class name or something, if you didn't have dependency injection and you had to do it manually or automated with a tool like Bash. And so to change or substitute specific words, we can use the sed command. And so I'm just going to show what that looks like. Here. We pass a kind of rejects type string where we want to substitute blue or pink. And so the S here is for substitute. Then the two strings we want to substitute, and g is just global. We only have one anyway, so that doesn't really matter. And then you have to pass the target file that you want to look at, which for us is file one dot TXT. So I'll just press Enter. And we see that the substitution was made. But if we cat file one again, we see that the contents haven't changed. So said has successfully done the translation for us, but it's not actually modifying file. So let's take a look into the manual to see if there's a way to modify the file in place. For a shoe man said and done the flags here. And yes, it looks like right here, dash I flag. We'll edit the files in place and we can save backups with the specified extension. So some flags like dash L here, this would be lined buffered. They don't accept an argument. But in this case the dash I has this extension argument. And so we're going to use that and modify our original command to include this new flag. So always start with the command and then the flag, and then the argument, which was the file extension for the backup. And just easy to remember. And unix doesn't care. We're going to call the file extension backup. Then we can continue on with the command as we did above. So just as normal while one dot TXT. So I'll press Enter. So first we'll check the contents of file one itself. Nice. It's been changed in place. The actual contents of the file had been changed. And we should also see a backup. Great, So it's the file dot TXT dot backup, which is the extension we specified. And we also expect to see in that file, the original file. So it's usually a good idea when editing in place with this dash I flag to include this backup. And actually on Mac systems it is required. So you'll always have that backup and so you don't risk any data loss. So that was just a simple example of using the manual to do a more advanced manipulation through the shell. But we're still missing one last puzzle piece, so to speak, to get a complete and complex view of using the shell. And that is with the various built-in input, output functions in Bash. And so we're going to get into that in the next lesson. And then we'll be ready to really write some advanced combined commands and scripts throughout the rest of the course. 8. I/O In Bash - Reading, Writing, and Piping: In the last lesson, we saw how we could use the manual to find a flag, to do some in place manipulation on a file. For said it turned out that there was such a flag, but many commands and bash don't have these built-in in place editing options, and we need to resort to what's known as input or output redirection or piping to accomplish our task. I'm going to show an example of each. So in this lesson, I've already copied over the file from the last lesson, the original file, my favorite color is blue. And so output redirection in Bash is done with the greater than sign, which is this. And so we need a command to actually redirect our output to. And so as an initial example of output redirection, I'm going to redirect the output of cat to a new file. So I'm just going to call cat file one dot TXT. And instead of letting it go to standard out here in the terminal, I'm going to redirect that to, let's just call it my awesome new file. And we'll also make it a TXT. And we press Enter. And let's call ls to see. There it is. And just to check what's in there, we're also going to cut out that text file. Great, So we see that cat instead of being displayed to standard output here in the terminal, it was written to my awesome new file, data.txt. We can also do input redirection, and that's with the less than symbol. So in kind of a reverse way, we can take the contents of our new file and send them into cat. So that would be calling cat. But taking the input from the file and we see the contents of that file printed out. We can also pass output of commands on through a chain of commands without having to read or write from a file. And this is known as piping in the syntax and batch for piping is with the bar symbol or the symbol. And so for that example, I'm going to pad out file one dot TXT. And I'm going to pipe that to our sed command, similar to last lesson. But in this case, we don't need to use dash I because this pipe is piping the output directly to set. So we can just call the substitution directly. Then we can call our output redirection to all this, call it new file dot TXT. So let's list, make sure it's their new files there. And we should expect the substituted sentence. Great. So that's an example of piping. So to follow the spirit of the last lesson, let's look at another command which like said, is able to do complex data manipulations, and that is TR. So while said is able to substitute full words or phrases on data, TR is more for translating specific characters in data. So let's take a look at it in the man. And one thing we notice right away is that there's no dash I option for a TR. It's relatively more simple then said. And so this is a perfect example of using input or output redirection to be able to use the powers of TR. So I'll back out of there. And a nice example, or an initial example showing the powers of TR is by translating all lowercase letters to uppercase letters. And that can be done with the following command. These brackets mean that it's a series, so all letters between a and z, and it is case sensitive. And there'll be translated to all letters a through Z capitalised. But again, how do we actually forward some data to this command? And again, I'll be using this file one dot TXT as an example. Well, there's a few ways. One of the ways is with the input redirection. And we see that TR is capitalizing the entire contents of file one. And then other way is with the piping method. So we can cat file one dxdy and pipe it to TR. Let's same man from above. And we see that works as well. My opinion, I prefer the cat and piping method since it leads to a left to right and easy to read command style, which we'll see later, is especially helpful when we move to writing full Bash scripts. And furthermore, a left to right fashion also enables us to use pipe in combination with output redirection to actually create a file of this output. So if I take that old command, but then add in a redirect to we'll call it file one, caps dx, dy. Then we can check the contents of file one. And we see that we've properly redirected that translated output into this new file. So in this lesson, we learned about both input and output, redirection and piping. So let's move on in the next lesson to see how we can also connect separate commands together when no reading or writing is required. 9. Bash Commands Part 5 - More Advanced Navigation and Stringing Commands Together cd, open: In the last lesson, we looked at how to read and write to files using redirects and also pass data through commands with the pipe syntax. But what if we want to issue multiple bash commands at once? And they don't necessarily have any data transferring through to them. To start off with an example, Let's discuss those hidden locations, dot and double-dot, that I mentioned in an earlier lesson. And we saw those with the LS dash, a command where we have this dot and double-dot location. In Unix systems, you will find this dot and double-dot location in every directory. The first of these, the single.php literally means here, it means this folder. And to prove that, we're going to call open on the dot location. And we'll see what our operating system does for us. And we see that since I'm on Mac and dot is a folder, it is a folder on this operating system. Mac opens it up in the Finder application and it shows this location. And so far for this lesson, I've just got the lesson notes file, and that's fine. Now the double-dot is the previous folder. So we would expect a similar reaction if we were to call open on double-dot, we would expect this Projects folder to be opened by the operating system, since the double-dot is also just a folder somewhere on the system. And it's opened in the other window. But it's right here. Try that again for the effect. There we go. So let's say we wanted to design a command where we could quickly open up the desktop folder. Perhaps your downloads go there and you want to quickly get to them in GUI from wherever you are on the terminal. One of the easiest ways to do this is to just chain a few commands together. We can cd into the Desktop directory and then use the we saw which would open finder or whatever GUI is on your Unix like system that you're using. And so there's two ways when data or input isn't involved to chain commands together. The first is simply separating each command with a semicolon. So let's try that now, we saw from the very first lesson that the standard route for my user here is users. Chris. And my desktop is just called desktop. So to get such a functionality, we would cd to that directory. That's the first command. And then we would issue open dot and semicolon for ending the second command. So let's fire that off now. And we see that it was opened. I don't have anything on my desktop right now, so it's empty. But you see it is the desktop folder here. Now, the one problem with the semicolon method is that if this command where to fail, this one would fire off anyway. It doesn't really care or know about this command, because the semicolon really means separate commands. To have these commands act as more of a logical chain that follow one another, we should use a logical operator. And in the case of doing them in series that is waiting for the first and then going on to the next logical operator we want to use is the end. If you have multiple commands that you want to run in parallel, you can call them all and chain them with just a single end. And batch will fire off all those commands at the same time. But typically unless you're doing some sort of complex task, the and n symbol is the one you want. So let's try that method as well just to make sure it works. I'm gonna go to the desktop. And we want to open. And we see that works as well. So this method would the logical operator works as well. But you might have noticed from either method here there's a weird kind of side effect. And that is that we literally do move to the desktop folder while issuing that, even though the final command is open, we're still calling CD. And in this shell we are moving to that directory. And so for a full, complete command, that would not affect the current location of where we are. We want to cd back into the directory we were issuing the command from. And so first off, I'm going to move back into that projects folder. So going into projects and bash commands and scripting course. And so we can copy this. And we need to add one last command. That is with CD. There's a nice feature in bash that when there's a dash, that means the previous location. So in this case, no matter where we are, we're only changing directory once and that's to the desktop. We're issuing open. And then we're issuing change to previous. That's exactly what this command cd dash means. So we'll give that a shot. That's great. We can see that the desktop folder was opened and we move back into our original location. So there's no side effects anymore from that command. And just to check, let's move back to the route wherein this user's Chris folder. And we can issue this. Once again. It's great. Opens the folder and we're still in the root. We haven't moved into the desktop. So in this lesson, we learned how to chain commands together when input or output really isn't the question and the task is actually just the commands themselves to follow. We saw how there's two methods to do this. You can simply issue multiple commands in a chain and separate them with a semicolon. But we discussed how would this method, if one of the commands fails, the other commands will continue on, which depending on what you are doing or what command you'd, you'd like to write that may have unintended side effects. So we ultimately resulted in using the logical and operator in which commands follow sequentially only if every subsequent command in the chain is successful. And this leads to typically a more predictable behavior. But obviously there's a point here where while we're in the terminal, we don't want to be writing or copying and pasting this entire command every single time we want to open the desktop, for example, or really any other complex task. So in the next lesson, we'll learn about creating what are known as aliases and then how we can save these aliases in our bash profile so we can access them at our fingertips at any moment. 10. Creating Aliases and The Bash Profile: In the last lesson following output and input redirecting and piping, we also saw how we could chain commands with the end or semicolon operators to chain commands that didn't require any data. But really now starting to feel like it's getting to be too much, right? We've learned at least a dozen different commands and almost as many flags for some of those commands. And it's really hard to remember when you should use them. And so computer scientists and engineers are no smarter and in fact were pretty lazy. And so there's a nice tool in Bash where we can define our own commands and we don't have to remember those long chains for doing tasks that we find useful. So in this lesson, we'll create some of our first aliases. And then we'll look into what's known as the bash profile, which is the standard place to save them. And so taking from our last example, the opening, the desktop folder chain of commands that was cd Users crisp desktop with the open at that location. And then the switch to previous command, we can run that and that's fine. And as I mentioned, it would be really annoying if we had to write that whole command down every time we wanted to open up the desktop and finder. And so we'll create an alias of a command that's much easier to remember. And so to do that, you write alias and then the name of the command you want. So for now I'll just call it Show Desktop. Because there's spaces and other characters in this command. I'm going to wrap the whole thing in double-quotes. Otherwise batch will get confused. And close those double-quotes and we'll press Enter. And so nothing's happened right now. This step is only the finding the alias itself. But now we would expect that if I write show desktop and press enter, we get the same exact functionality as our long command here. And in fact it is the same long command. It's just been aliased to this show desktop command. And the other nice thing is everything that comes with bash also comes with your aliases. If we start to write show desktop, it will auto complete and works as expected. So aliases are super powerful, but there's one drawback. We can't just define the alias in line like this and expect to use it wherever. So for example, if I open up a new terminal and I write Show Desktop, bash is going to complain and say that Show Desktop is not found. And the reason this happens is because every time you open a new terminal, only a small set of files are opened and loaded. And of course, this one inline command that we wrote over in this terminal does not exist in either of these two terminals. However, one of the locations that is red and processed is your bash profile. And for Mac that is at the root. So I'm gonna just cd to the root. Cd with no arguments brings us there. And we're at the users Chris folder. And the default bash profile is the bash profile, but I need to open that so I can edit it. So I'm going to do nano bash profile. And most of this stuff at the top is built-in. And it may vary depending on what operating system you're using. There's global settings like how Much command history you want to keep and store. And some other global settings depending on the operating system. So you can keep your aliases in a separate bash aliases file. That's up to you. As for me, I've always kept all my aliases and custom functions right in the bash profile. And so I have a few of those, but let's just focus on the one that we've just written, which is our desktop command. So it was great. Now so we can exit out of nano. We can save that. And now, one of the most common gotchas when you do this, you've think you've updated your bash profile. You're going to look at it again. The alias is there. It's defined correctly, no syntax errors. And you go to Show Desktop and it still says it's not found. And the reason is again, this environment issue. The bash profile is only read when you open a new terminal or start a new terminal instance. To do that without opening a new terminal, we need to use a command known as source. That means literally source whatever is in this file into the shell. And so we'll run that now. You will source the bash profile. Press enter. Mine takes a little 1 second to run just kinda so big and I have many custom functions. But now we should expect that the show desktop command should work. And I've made a typo, that is users. And again, you have to, after modifying, you always have to source the batch profile to get those aliases in. And it will try again. Show desktop. And it works. Now the benefit is if you want to use it right away, you have to remember to do source. Otherwise, it's always going to run when we open a new terminal. And we've successfully created our very first alias. Just keep in mind that if you are following along with z, SH, for example, or a different shell, the profile maybe in a different location. For example, the Z SHA1 is the profile. But I don't know all of them. I only knows the SH and bash really. And I don't know the location or standard locations for each. So you'll have to look those up depending on your shell or your operating system. So in this lesson, we learned how to create aliases for our commands and that we could save commands with a remember trouble name, and it prevented us from writing long chains of commands to do complex tasks. We saw that we could create aliases directly in the terminal. But those aliases were alive only for the lifetime of that terminal. And a good way of saving aliases if you want to keep them permanent, is to write them right in your bash profile. And we also saw how to use them right away. You need to source your bash profile or open a new terminal after saving your bash profile. And so while aliases are powerful for single chain commands, we sometimes need to provide input or multiple inputs to our custom commands. And a better way to do that is with bash functions. So in the next lesson, we'll look at how we can write Bash functions, put them in our bash profile, and use them to pass parameters to our custom functions. 11. Creating Functions in Bash: In the last lesson, we saw how to create bash aliases, which was a way to combine commands that complete a specific task. We were able to save these aliases using the alias command, essentially creating a new name for our tasks. But sometimes aliases aren't enough to accomplish what we want. We need to pass in various input in our commands. So far, throughout the whole course, we've been writing in letter for letter, the exact commands we've needed. However, if you want to have variable or dynamic inputs, will need to learn how to pass parameters. And to pass parameters will have to write functions in Bash. Also for the first time in this course, we'll actually be using the lesson file interactively, writing functions in the file, and then sourcing it just like we would the bash profile. In the next lesson, we'll be writing aliases and functions, right in the bash profile. But for now, we're going to keep it simple and just write functions in this empty shell script here. To learn about a good use case for functions in Bash, we're going to learn a new command called grep. Grep is a file patterns searcher. It can search single files or entire directories for a certain phrase. It also supports regex to show off the powers of grep. I've already downloaded for this lesson a full copy of the Hamlet script by Shakespeare. And to use grep, we start with the command grep and what we want to search for. And just to keep it super simple. And because Hamlet is kind of a depressing story, I'm going to search for death. And then the second parameter you pass is the file or location you want to search. So we want to search this file, the Hamel TXT. So we get quite a large output. And for first-time users, it's not very clear what exactly is happening here. But what we do notice is each line includes death. So grep is searching for something. First flag that we're going to pass to make this more clear, I'm just going to press up on the keyboard to get the command back. First flag will pass is color. Now this is more clear. Grep highlights what we're searching for. So it's looking like these are multiple lines from throughout the script. And we can also get those lines as well. There's another long command, double dash line number. Now, you can also pass dash n to get the line numbers. But this flag is much more clear. So I'm going to use that one. Going to press Enter again. Great. And we're getting all the different lime numbers where the word death occurs. Now I'm going to try and search for one of the most famous lines. Great. And we see this line to be or not to be appears on line 19, 12. Another thing about grep. I were to search the fall and just put it this way. When I type in the two b comma naught to be, we see that it's no longer picking up that line. And that's because grab, like almost all tools and commands in Bash is case-sensitive. And so here there's yet another fly we can pass in to make the search case insensitive. And that is the dash g flag. I need or not to be. Great. And now so grep is still finding this, even though the T is capitalized here. The case insensitive flag is still finding this phrase. And now to show one more flag with grep, I've also prepared this folder of many texts. And if we cd into there really quickly, I also have the Hamlet texts in here and also the Frankenstein and Romeo Juliet TXT. So I'm going to go back to our course folder and search through my history. Get to the original command. And I want to search for. Let's do depth again, since these are all still kind of tragic stories, unfortunately. And to search a directory, you can use the dash R flag, and we want to search the many texts directory. So let's see what comes out here. Great. So not only does grab show us the line of the occurring, it's also showing us the file where it occurs. So grep is quite a powerful tool and this is just scratching the surface of what Grab can do. It can handle regex and do other advanced things. And so it's quite useful for when you need to find something in a large project. Now finally, to the goal of this lesson, which is using functions in Bash. Let's take a look at this large grep command. Now, I don't know about you, but I don't like writing this giant command every time I want to search through a file or folders. But now we also see by the syntax of this command, we have two inputs which will need to provide if we were to write an alias like command to use those two inputs are the query itself, then the location we want to search. And so is clear then we couldn't simply assign this to an alias. We could, but then we would always be searching a folder named many texts and the word death, which isn't very useful if you're not searching some of the English classics. So we're going to write a function where we can pass these two parameters in as variables. So to get started, I'm going to Nano the lesson file, open it up in an editor. And to write a function in Bash, it's very similar to all other languages. You start with the keyword function. And I'm going to call this simply search. You use the two parentheses and wrap the function body in curly brackets. Just space a little here for formatting. And when parameters are passed into functions, the way we use them in the function body is with the dollar sign starting at one. And then going up to however many parameters you've passed to the function. That is, if I were to be in the terminal and I would write something like search Hello, World. In the body of this function. If I wanted to access hello, it would be in dollar sign one. And if I wanted to access world, it would be in dollar sign two. So I'll get rid of those. Just to illustrate clearly. I'll also read the command here. We had what did we have? We had grep color, we had the insensitive flag, the recursive flag. And we had our search and then the location, which was something like x or so. So in order to turn this into a function where we can pass the two parameters. Take this function. Then we'll do following the same pattern that grep steps. We'll pass in parameters 12. So I'm going to get rid of this. And so it turns out search is already a built in alias, at least here on my Mac. So to illustrate this function that we've written, let's use a function name that isn't already command. We'll just call it use grep. And so we'll save that. And so just like in the last lesson, how we sourced the bash profile, we're going to source this lesson ten shell script. And everything we've defined in declared in that script will be pulled into this environment here. So right now if I call you scrap, we expect batch to yell at us. It can't find this command. But as soon as we source the lesson shell script, we can try and call this. And now it's going to yell at us anyway. And actually what it's yelling at us for, we see, we're getting there. It's yelling at us because grep expects some flags and input. And so we simply need to pass in those parameters that we've defined in the function and it should work as expected. So just using our original example, I'll type in use grep, death and Hamlet. And we can also do are to be or not to be. And we see when I do this full command or the famous To be or not to be lined, we're not getting exactly what we expect. And in fact, it looks like Grab is only seeing the two and not the entire phrase. And this is because I've made a common mistake with bash functions in their parameters. If we hop into the lesson, we see actually that this parameter is being evaluated directly. So to explain what that means. And so Bash doesn't carry over those double quotes or single quotes. It's pasting literally the value of the first parameter passed into that location. So we need to modify our function slightly. And so I'll reopen the shell script. And we should wrap the first parameter in quotes like this. So the entire first parameter, when you as a user of the function, don't forget the source it when you as a user of the function accesses the US, grab. This whole value here, not including the quotes, is evaluated as the dollar sign one. But then it's put back into the quotes in the grep function. So be aware of that for when you make your own functions with similar string type parameters on, I've forgotten the two here. And we see the function is working. And so for another quick illustration of using a function in Bash, we're going to learn another command in this lesson in that is the history command. And so history simply gives you a list of all the commands that you've entered in this terminal. Now there are ways of configuring it to be global. That is, when you open different terminals, you may see different histories. But I'll let you look up those settings. And a useful function we can write combines both history and grab. And we can use something we've learned in a previous lesson, which is piping. So I'm going to open up the script again. And we'll go ahead here and write a second function. So you can probably guess perhaps where I'm going. I'm going to call this one search history. Have our curly brackets. And so this is going to be the history output. And I'm going to pipe this directly into grep. And then I'm going to actually take these same flags. There's no need for the recursive flags since we're not searching anything in here. And in this case, we only need the first parameter. We don't need to pass in any file because we know the input for graph is coming from history. So we only have this first parameter of the thing we want to search for. So I'm going to exit out of there. Save that file. Again, don't forget to source it. Let's just search history for grep, which we've been using frequently. And we can see all the uses that we have issued recently in the terminal using grep. So in this lesson, we got an initial look at how we write functions in Bash. We saw how to accept parameters in our functions with the dollar sign, $1, sign two, and so on. And we also wrote a fun search history function that can be used to find commands in history based on a simple keyword search. So in the next lesson, now that we've learned aliases and functions, we're going to hop directly in the batch profile, and I'm going to walk through some of my favorite bash aliases and functions. Ones that I use almost every day and help me remember how to navigate in the terminal. 12. Create Your Own Bash Profile: Now that we've learned the basics of aliases and functions, we can do something a little bit fun. In this lesson, I'm going to share some of the most heavily used aliases and functions of mine. And note that the ones we cover in this lesson, you don't have to take these names or even the commands. But perhaps some of them you may find useful or you can tweak for your own purposes. And so we're going to hop right into the bash profile and write them directly there. So I'm going to issue cd with no flags or parameters to get to the root directory. And as we know, the bash profile is here and we can open it with nano bash profile. So I'm going to scroll down and we have our show desktop alias from before. And so I'll just start here. And so the first command most heavily used is actually quite Meta. It's actually what we just did. It's opening up the bash profile itself. And I alias that to simply proof. And so if you want to open it nano, you can use Nano. And this is my location. Again. Make sure to change this location to where your user is. And for example, if you're not in an SSH and your actions on a desktop or interacting with a GUI. You can also, for example, aliases to use code for Visual Studio code or perhaps Sublime Text and then the same bolder or same file path. So I'm going to comment that out just to stick with nano. And the second one is also quite Mehta and that is sourcing the bash profile. And I alias that to a single letter just because I use it so often. And you can just quickly press S and then Enter. And that is sourcing this bash profile. So it's really easy to remember. After issuing probes, you go into your bash profile, you do the edits, you need. You back out, save the file, and then quickly press S and enter. And then you know, whatever changes are active in your current terminal and you don't have to open a new terminal. So prof in S R2 that I use very often whenever I edit the batch profile. The next one is more of a navigation one, and that is what I call LK. And this is just Ls with a bunch of parameters. So it's the list flag, the human readable data format. In kilobytes. The a for showing all of them and a few others. And actually what I like about this flag is that L and K are right next to each other on the keyboard. You don't have L and S which are separate fingers on the keyboard. I know this sounds like an over optimization, but when you're interacting with a terminal over SSH, for example, where you don't have a GUI, you're going to be using ls a lot just to see what file you're in and what folders you're looking at. And so this quick LK with just your two fingers is rather nice. And I've even done, at least on my machine, I alias the reverse just in case I'm too fast and it's a typo. So it's the same exact command. Now the next or also for navigating. And most of them we've seen already or some version of them. Next one is show in that is that So I don't like writing open dot. First off, it's two separate things, the type and so I just simply ratio and that does what I expect. It opens the folder that I'm currently in. Then I also have back, which is that cd dot dot. I have the previous which we also saw from our remarks, show desktop command and the home, what I call home command. And let's cd without any parameters or flags. And so these we've all seen actually, and really these aliases are more just for me, they're easy to remember and I know or can expect exactly what they're gonna do just based on their names. Another one I have another single letter, one that I use a little bit is clear. Let's just see. Another fun one you can do is a beep. And literally what this does is echo out the sound of the Unicode for bell. You have to check with your operating system if this works, this works on Mac. And what's nice here is you can issue this beep command after a long running command. So what we've seen in other lessons, for example, if I had just for writing in pseudocode here like some long command, then you can always do and nbsp. And so Bash will wait for this to run and when it's done, you'll get a beep. So you'll know that the job is done. And in the coming lessons we'll see how we can throw this in a loop. Because one beep, you don't always notice. But if you do a bunch of beeps in a loop, like five beats in a row, then be alerted to the fact that the job is done. So the next few are just folder locations. And as a side note, these four locations I've really liked over the years as a developer to kind of divide where I keep my projects and how I organize them. So the four folders that I have, one I call open source, one I call projects, one I call playground, and one I call enterprise. And all of those I put right in my root folder and I do this the same on my remote machines as well. So the open source folder. This is where I keep all my Git repositories for projects where typically I'm not the owner, but perhaps a contributor. This is a really busy folder, for example, during October Fest for me. The second one is the Projects folder, which I just alias as PJ. It's easiest for me to remember. You could do proj for example. And again, these are all just suggestions. None of these are must use aliases. And these are my side projects. So they're perhaps not for profit or really well done and polished. Just some of the projects I've done in the past. Perhaps there's a small website with it or something like that. That's what I keep in my projects. The third boulder is the playground folder, which I alias just to play. And this folder is where I go and I quickly want to download a repository and dig into some source code to see what's going on there or quickly get a look at a project. So that's the playground folder. And then the final one is the enterprise folder. And I alias that with EP. Now this is the folder where I keep all my for-profit projects, projects for customers and consulting work and all things like that. So these are the real solid projects where I can expect a high-quality of whatever Git repository is in other files are in that folder. So these four aliases are quite nice because I can simply issue them. And then I know I'm in the correct directory and I'm ready to do whatever I need to do. Typically it's something as simple as downloading a Git repository and then looking at the contents in there. And I realize I've made a typo here. And two last ones, which I use, I alias PY for the Python command to run Python scripts. And similarly with Python three is PI 3. So those are some of my most common aliases that I use. I hope you find them useful or perhaps you can think of some of your own or how you'd like to organize your own machine. So I've refined this system for a few years now, works really well for me. But of course, feel free to make your own aliases and commands. But maybe this gives you a bit of background to think about. You want to organize your system in terms of functions. I have quite a few in my own bash profile, but a lot of them are kind of weird edge cases or things that aren't really relevant to this course. I have commands for converting videos and gifts and things like that. So I'm just going to include some, actually, actually some get utility functions which I use quite a lot. So the first one is one I've called push all. So that function is like this. All it is is a git add dot. All the changed files in the Git repository. It's git commit all and then git push. All. Initially looking at this function, it looks like this would just cause get to commit and push everything immediately. But actually that's not the case kind of built into this function automatically because of get on the commit step here, the editor will open and it will ask you to add a commit message. And the nice thing is if you type this too quickly, you know, you've added all your files and you're ready to commit and you cancel out of that editor. The push won't go through because Git has a built-in rule that you can't push with an empty commit message. And another caveat with this function is that it is adding all the file. So this is great for your own side projects or your personal projects. But just keep in mind if you're working for a client or your own company or somewhere else where you need to separate commits, perhaps with a ticket number or separating files by ticket. This probably isn't the best alias for you. But in terms of side projects and little projects I've been doing, It's a great utility function. You just type push all, you type your commit message and it's off. So kinda following that push all I have a few merge functions. And so if any of you have seen my pipelines course, I typically run in a develop, staging, and master branch system for all my Git repositories. And so these following functions rely on that distinction. So you will need to have a develop, a staging and master branch in your Git repositories. So I have merged to staging. And that is the first you move to the staging branch. You merge to develop with no fast forward. And that is so you get a commit for the merge and that makes the history lookup easier. And then git push and I have an echo message here. I just say push to staging, successful, putting you back on branch, develop. And I do just that. I go back to the develop branch. Then I have to merge to master functions. So one is directly from develop. And those are for the sites where, for example, maybe it's just a personal project site. And you only have a master to fire off your build process, for example. And that's, those are the times where you're merging directly from developed to master. And actually in these projects, I don't have a staging branch. I just have the master and develop branches. So this is very similar. And likewise, I have the merge to staging, merge to master from staging. And I've forgotten the last line here. And the final one I have is called full merge. And that actually uses a neat feature of bash that even inline in this profile, we can nest functions or use functions that have been declared right in the file. So let me show you what I mean by that. So we have this full merge function. And what a former for me is at least as how I've defined it, is merged to staging, which is this function. And then a merge to master from staging. And so even though these functions are defined in the same exact file, because they're defined ahead of this function, we can use them in the function and bash knows what this means. And actually if we look at the command from a few lessons ago, this showed desktop. And what we can do actually following a similar pattern, but for aliases instead. For example, if we created an alias desk, which would bring us to the desktop. And this the S Again. We could combine this desk alias, Show and priv all to get the same effect and it would be even more readable. So we would have to define a below all the other aliases that are used. But just for a short version, let's call it show desk. And that would be desk, show. And then prove. So you can even nest aliases within other aliases or similarly functions within other functions. Just note that the syntax here, it's not like JavaScript. You don't call the function with the two parentheses, you just leave it like this. And so again, I just want to know with these bash commands, they are rather specific and they're typically only useful if you're working by yourself or in a very small team. So just be aware. Built into these you are committing and pushing all the files. But I've designed these for how my workflow works. They were pretty well. And if you have a similar develop staging master branch system, maybe you can use these and modify them to whatever needs you have. So I will include all of these aliases in the lesson shell script. So you'll actually be able to execute or source that Shell script just like you would a bash profile. And of course feel free to copy and paste it into your own bash profile or tweak them and modify them to however you'd like. So in this lesson, we opened up the batch profile and I walked through some of my most used and favorite aliases that I use almost every day. And I also included some get utility functions that helped me with my Git workflow. 13. Bash Commands Part 6 - awk or gawk: Now that we're getting more uses of the terminal, in the coming lessons, we're going to cover more advanced commands and bash. The first of these commands is OK. That is a WK. We saw in less than 10, we can look up lines in a file using the command like Grep. And in an earlier lesson, we saw we can make replacements with a command like said or TR. But what if we want to parse certain rows or certain columns of data without looking for a particular term. And we don't want to modify the data itself. Auc is the tool for that. Note that you may have to install AUC or GSC, which is GNU OK, depending on your OS. For example, if I check for GSC here, I don't have it, but OK, I do. But typically no matter what Unix or Unix like OS you're using, some form of AAC is included. I've prepared in this lesson a list of countries and their populations in data.txt. And these are a tab separated. So just quickly cat out what's exactly in there. Looks like a mess in terminal mode, but I promise you they're tab separated. We can use AAC to quickly find a given row with the following syntax. Type in 4k, then NR, and then the row that you'd like. So just randomly, I'll take the third row and I'll print it out. Now, the syntax in this line here is specific to AAC. You'll have to read in the documentation if you want to do more advanced things, supports IF statements and replacements and all sorts of things. For now I'm just showing a little bit of a introduction into this tool. And then as the second parameter, the file we want to parse, which is our data.txt. So it looks like India is the third row. If we want the third row and the first column, that would be not print. Should be print. And so on, can move on through the columns. The data isn't super clean since I've taken it from Wikipedia, you can see how quickly I can parse this tabulated data. As another more real-world example. A NodeJS Damon I frequently used called forever, has a command where you can list the running processes. And for this lesson, I've already started up an example process in the background. So you can imagine if you had a production server and you were running a node instance somewhere on it, you could be using this forever tool. I've used it in some of my other courses. So that command just to list the processes is forever list. A big list, it runs over the lines. But for example, if we wanted to parse out the location, which is this Durer column, that is 123456789. And so we can pipe wherever is output into. Ok. That's going to be the second row. And I believe if I've counted right, the ninth eight, it's 0 index. And I've made a mistake. Apparently that's row 3. So log file I'm still off. And the 10th. And that's how you would parse out that type of output. So for example, if you had a continuous integration or continuous deployment job, you could run this command and compare this string. For example, if you're looking for a specific project to restart, and if you don't get this string or the string doesn't contain what you expect when you would start a new instance, for example. Another command which is also very powerful and bash and also has the similar table style output is top. And top is basically in, in console Task Manager. So it lists all the jobs that are running. What command they were started with, the CPU they're taking up. And you can see as I'm recording this course, t OBS application is taking up almost all my CPU. And this is updated in near real-time. So we should be able to AUC this as well. This is 123456789, 10, 11, 11 would be the most CPU consuming command that's running. So the 11th row and then perhaps the will print the second, third columns. So we can try that now. Because top is interactive and updates the CPU usages only at certain intervals with the past a few flags to get exactly the output we want. And then we'll parse it with AUC in order to get the top CPU using process at the current time. And so the command I ended up with this top with bash i1, which means update the CPU usage at every iteration. And then we'll do that three times to make sure that the current CPU calculations are reflective. If there's any long running processes and will only take the top 10 processes. And I put them out to a hop dot TXT. So actually what you'll get in there are three iterations of the top output in this TXT file. So just run that takes a few seconds since it's literally writing it's iterations there. And then we can pipe that to our AAC file. And it ends up being, at least here in my Mac. It's line 57. So first I'll print that whole line. I need to pat. And we see we have the OBS, which was using over a 100 percent of CPU. It's not perfectly accurate the top calculation. But then just to simplify the output, we can print 23. And of course combined, we can use the logical operator. Put in and in between the two. And I'm going to copy and paste this line. And it takes few seconds to actually get that top output and it prints out the most resource intensive process. In this lesson, we learned a little bit about AAC and saw how powerful it is to quickly parse specific parts of output. And it's particularly useful in output that is table-like and can be parsed into columns and rows. So in the next lesson, we'll look at two commands which are used for retrieving data from the web. 14. Bash Commands Part 7 - wget, curl, and traceroute: Last lesson, we learned how to use AAC, which was a powerful command. Use the parse rows and columns from data in the terminal. In this lesson, we're going to learn about a few commands I can interact with the Internet. The two main ones being w getting curl. W get is more simpler of the two. And it supports only HTTP, HTTPS, and FTP protocols. It's used mainly to download files from the web or an FTP server. For example, to download the source of Google. You simply type W get and then Now by default, W get has some logs. We can see that we were redirected to the www site. Follow there. And WPA automatically saves the output of the site to index.html. And we can see that. And if we cut that out, we can see the HTML form of Google. Clear the terminal. And just for example, or my site, my blog. W get will also download that and it'll even append a dot one. It won't overwrite the index.html. And if I cat that index HTML1 out, can see I've got my Google, Google Analytics tag there. And there's some stuff. My email, yup, looks like my blog. Now to redirect the output from W get to a different folder. We can use the dash P, dash capital P flag. A lot of resources you see online say to use the dash o command. But if you look into the manual, what this will do is if w is downloading multiple files or detects a download of multiple files when you're going to a URL, it's going to append all of that output into one file, which isn't exactly ideal and perhaps unexpected. So to let W get manage its own files, but redirect separate possible files into a folder. You should use the dash capital P command. So just to illustrate that, I'm going to call the same two sides again. So we'll do we will, for We can even see in the output here, the log output. It's putting it into index.html in the Google folder. So it creates the folder and everything. And then for my site, I'll just call it blog. And same thing. It makes that folder even check. We've got the Google on the blog. So that's all working and that's great. Now the other popular command for downloading webpages is curl. But curl is a bit more complex and it's used for more than just downloading. With curl, you can build and craft the entire requests that you want. So you can pass things like headers. You can change the method, for example, doing PUT and post, things like that. So for example, to message a Slack bot, we can use curl to post to a Slack web hook. So that would be curl, the dash X flag for the method, the dash H lag for the header. And we want to do content type application. Json can pass in the data. And it expects a JSON object of this form. I'm just going to say curl is awesome. And I'll paste in my webhook going. You won't be able to see it because it's protected and I don't want people spamming my web hook channel. And we can see for my server bought, those last two messages have been sent here. Another cool usage with curl is this function which I've lovingly called super curl. Curl actually keeps track of all the various times involved with the request, like the name lookup, the connection time, transfer time and things like that. So actually paste in the super curl into the lesson shell script. So we'll open that now with nano. And I'm just going to paste it in here. So this will be in this lesson's shell script. We can access it there. Once you've downloaded the course repository, I'll just save that. And again, we have to source that. And let's super curl Google. Okay, so we see we've got the lookup time, the connection time. So that's a quick overview of W get and curl. They're both very powerful. You can look into the manual to see all the features and functionality they have. You can do, for example, a range of URLs and download them, which is nice if you want to fire off batch jobs. Or for example, if you're retrieving data from an API that can be useful that way. Traceroute is another useful command that can help find what network path is taken to any given site. And if you're really stuck with why you can't connect to a site. You can look at the output of traceroute and perhaps it can point you to some hints as to where the issue is. So just as a simple example, I'm going to trace route taking Google again. And it's done. So we see this is actually my local host here on my router. This is my ISP Lampert. This we could look up. I'm not sure where this is. I'm in Western Australia right now. And a useful site here is Epi Info dot io and search that also that's dorm virion. This is Western Australia, and then it looks like it's going to Zurich or this is some Swiss that CH server can check that. Yep, that's in Zurich. And then it's going here. These are unnamed, just draw IPs. And then it's jumping all the way to Mountain View where Google is. So that's just a quick example of traceroute. So in the next lesson we're going to look at even more advanced commands. And then we'll start getting into logical operators, if statements, else, statements, cases, and more. 15. Bash Commands Part 8 - tree, free, ifconfig, memory pressure: So by now hopefully you're starting to get a feel for the terminal and bash and some of its commands. Perhaps you're starting to use Bash in the terminal in your day-to-day developer tasks. In this lesson, I'm going to rapid-fire through some commands that I don't always use on a day-to-day basis, but are powerful examples of bash nonetheless. The first one is called tree. Tree is a perfect example of bash in its philosophy. Like all commands and bash, this command is dedicated to a very niche task and that is making a tree of the folder structure wherever you are. And remember, if you want a quick snapshot, you can just use bashes output redirect to save the output of tree. And so we're actually going to do that right now. First, I want to print out the working directory so I can redirect the output here. It's going to copy this. So I'm going to move to my blog, cd to the root, and then the enterprise folder and my blog. Now, this blog is an MPM project. So if I were to just issue tree dot, when tree hits that node modules folder, there's so many dependencies and sub folders in that folder, that tree is going to hang and kind of blow up. It probably would work eventually, but it would take a few minutes to run. And so we can use the capitalised I flag to ignore certain patterns. So I'll use that flag with Node modules. And we just want to redirect the output to, I'll just call it blog tree dot TXT. Just press Enter. Now I'm going to cd back into the course repository. We issue ls. We should see that blog tree and if we cut it out, we see our nice folder structure here. So these are all my blog posts here. I've got some other assets, pictures, React components, unfinished draft posts. So it looks like the tree command worked fine. Another useful command is free. And free is a command which shows the available memory on a system. Unfortunately, the free command is not available on Mac, but I can quickly SSH into one of my digital ocean droplets. And we can issue free here. Now by default, realists, these total US free, shared the cache and available memory in bytes. And we can pass the H flag for human-readable numbers instead of flights. So we do free dash H. We see that it's listed in megabytes. And so we can see I've got about a gigabyte free. I'm using about half of that. And I've got about 216 megabytes available. And I'm going to exit out of the SSH. And the equivalent command on a Mac would be memory pressure. And this command is actually more detailed. And the free command, There's a bunch of stats and swap info. But perhaps the most important is this last line here, and it gives you the system-wide free memory percentage. The final command will look at for this lesson is IF config, this command will show you your entire network interface on your machine or system. So this command is very useful when you want to know your local host or perhaps your IP on your local area network or Ethernet. So I'll just issue that now. And we've got the full list of our network interface. So two important ones here are the LO 0, which is your local host. Typically it's the 12, 7.1, but it can be something else with custom configurations. Another important one is the EN 0, and that is the IP address on your local area network or your Ethernet network. And so this machine here, my laptop is 19 to 16, 8, 0, 25. So in this lesson, we learned first about the tree command, which is a nice command to get an overview of a folder or a project structure. And we use my blog as an example and redirected the output of that command to a text file. We then saw the free command, which is available on Linux systems. And we saw that we could pass the H flag for human-readable info. And that command gives a good overview of the available memory on a system. We saw that the equivalent command for that on a Mac is memory underscore pressure. And we also issued that here locally on my machine to get the free percentage of memory available. So in the next lesson, we'll move away from just the command based lesson and we'll look at logical operators. So if else, else-if and K statements. 16. Logical Operators - if, else, and case: In this lesson, we're going to learn how to use logical operators in Bash. So if else-if else and K statements. And like all their lessons, I've prepared a shell script. It's currently empty. And for this lesson we're actually going to use a real code editor and not just nano to edit the shell script. The syntax highlighting that we get in a real editor is going to be very helpful for this lesson. So I've opened the shell script in Visual Studio Code. And to get started, I'm going to just write a simple function that will compare two strings. So it will just tell us if the strings are equal. So just very basic to start off here. So I'll just call it compare strings. And the syntax for an if statement is you start with if. You do double brackets, square brackets. And then what we've learned from previous lessons, we know the two parameters passed in will be dollar sign $1, sign two. And then we can just use equal equal. So very similar to other languages. Then we'll use the keyword then. And then whatever we want to occur if this statement evaluates to true. And so we just will say the strings are equal. And to end the if statement in Bash, you just type Phi, which is just if backwards. So I'll save this. And we're going to source that shell script. And let's give it a test here. So compare strings. I'll just do hello and hello. The strings are equal. And something like not hello doesn't print anything. So I'm going to go back to the script. Now it's very similar for comparing numbers, but we're going to use arithmetic expansion instead of a string context. So really the only thing that changes is instead of these double brackets, we use parentheses. So I'll call this function compare numbers. And otherwise the syntax is the same. So these parentheses tell bash to evaluate the statement in an arithmetic contexts. This is a string context. And similar. And close the if statement. Source again, this file, we'll just do 1110, nothing. And the syntax for else. You just put in the else statement. There is no then when you're using else. And same thing here. So there's that and everything checks out. And to show an if else case, we're going to write another function. This one's going to check if a number is positive. Again, we'll use the arithmetic expansion. So if it's greater than one, will just say positive. And the else-if is not else if, it's just L if. And again arithmetic expansion. Now I have to check it's negative. And do then. And then our else case. Once again, the else doesn't need the Then keyword. And we can close the if statement. Say this again. First that script is positive. If it's negative, one, positive 200. Now one caveat with this function. If we enter a non-number. So just like a word, we're gonna get this third case here. And that's because in this arithmetic contexts, the default in Bash, if it can't access it as a number is to just do false. So this is false, false through here, this is false. And we get to this case. So you could add this caveat, for example. But if you're getting into tasks where types are important, then you should start to rethink if what you're doing in Bash makes a lot of sense. So typically, it's much easier to do simple tasks where you know exactly the type of inputs you're going to get. For example, a string input or number or so on. And as another example, we can also write a is even function. Again with the arithmetic expansion and the modulo operator. If that's 0, then we know that number is even. Not even save source that file. And we see that's working just fine. And now that we know a little bit about if statements, I wanna kinda return to the lesson where we learned initially about these parameters passed into functions. There may be the case sometimes that you want to call an external script. For the example in this lesson, I'm going to call an external Python script. So we're going to create that now. I'm just going to call it test. And we can open this as well in the editor. And since this course isn't about Python, I'm just going to paste this in this script. It'll be in the lesson source in the Git repository. But basically, what this script represents is a Python script which is at least one argument. So it will yell at you if there are not enough arguments passed in. And otherwise the third, fourth arguments are optional. And so if we wanted to build a wrapper function where we could call this script from anywhere across the system. We have to start thinking about how we can handle this kind of case where we always need to pass in at least one. But 34 are optional. And initially you might say I, yeah, we can use if statements to check if the parameters exist. So that is possible. And I'll show an example of how we can do that. But ultimately we're going to end with a much cleaner solution. So let me first illustrate the checking of parameters which you can also use for other functionalities. So I'll call this one run Python script. And the way you can check if a perimeter is empty is with the dash z operator. And so we're going to do, we can build such a wrapper function using another if functionality to check if each parameter required is actually there. So I'm going to call this wrapper function run Python script. And in this case the string context is okay. And the operator we want to use here to check if it's empty is dash z. So we do, actually what we want is if the parameter is not empty, then we can pass it on. I'm going to do then we want to call our script. So we'll use the Python three binary. That's the location of where we are currently that script. We just paste it in this test dot PY. And we know if this parameter is an empty. Then we can pass in all three. And then elsif, and we can go straight down the line for all of them. If there aren't any, we don't wanna do anything. Or perhaps you could throw in an else. And just as a warning or a note to the user. So we can save that and we'll source. We can check, for example, with a single argument, with two arguments. Something else. And if we call it without any arguments, should yell at us. Right? So we've safely bill a wrapper for this type of script where you would expect at least one argument but 34 would be optional. However, you may have noticed, while this was a good example to illustrate how this z operator works, that is, checking if a parameter isn't empty. This kind of flow isn't very clean. And it definitely feels like there's a way we can do this better. And there is, there's a special parameter in Bash. It's not a number, but it will reflect passing in all of these based on how many there are. So if there's only one, it passes it, if there's two, it'll pass them and so on. And that parameter is the dollar sign at parameter. And so we can simplify this entire script. I'll keep this one just for reference. And I'll call it a new one. I'll just call it clean. And really all this logic falls out. And we can use this special parameter, the dollar sign at. We do lose this warning, but the same type of warning is built into the script itself anyway. So that's not too much of a problem. So we're going to source that script again. And we'll see if we get the same behavior. It looks okay. Hello world and the something else. And if we don't enter any, this is actually the scripts warning and not directly in here. So that's a quick use case of how you can use this at. Parameter to pass in all parameters, for example, to a Python script. And as the last part of this lesson, we're going to write a function that utilizes a case statement in Bash. And I've always thought case statements in Bash are kind of weird. Usually I have to look them up to remember the syntax. But to complete this lesson, we'll write a simple one just for completeness. So I'm going to call this one some process. Literally. And the syntax is case. And then the variable you want to compare. In this case, we'll take the first argument passed into the script. And then you say in. And then the cases are as follows, and they're literally hardcoded in. So let's imagine for this some process, we have a start, stop and restart command that we want to pass in. Each of these commands should fire off some separate logic. And so you write each of the cases, right in the case of the mean itself and followed with the parentheses. So the first one is, I said start. We can just say starting into close the case, you do a double semi-colon. For the next case. We have stopped. I'll just say stopping, close the case, restart. And then the default case isn't default unfortunately, but it's this star with the parenthesis. And we'll just say unknown command, doing nothing. And close that as well. And I've seen forgotten here to close this. And to end the case. It's just like an if statement. You do case backwards. So I always thought bash was a little bit strange with that type of syntax, but that's what it is. So we'll source that script again. And we can try this out. And we'll say some process start. Okay, it's starting, restart, it's restarting, stopping, and then something foolish, that unknown command doing nothing. So that's a case statement in Bash. So in this lesson, we learned how to use logical operations in Bash. We started off with a simple if statement comparing two strings. And we saw in string context in Bash, we can use the square brackets and the typical equals equals symbol that's used in many other languages for logical comparisons. For numbers, it's best to use the parentheses, which tells bash to evaluate the inside statement in an arithmetic context, we also saw how to check if a parameter passed in is empty or not empty, in this case, with the Nazis and the dash z operator. And we also learned about bashes, powerful dollar sign at Perimeter, which represents all or as many parameters that are passed into a function. And we saw that this is very useful for when you need to pass multiple parameters into an external script. Finally, we ended the lesson by writing a simple case statement, checking out the weird case syntax in Bash. And the example we used could be some sort of function for a type of process that is Start, Stop, bubble, or restartable. So in the next lesson, we'll continue using if statements, but we're going to learn how to handle errors with bash and parsing out specific error codes and doing something with those error codes. 17. Error Handling in Bash: In the last lesson, we learned how to use logical operators in Bash, so things like if, else and case statements. In this lesson, we're going to learn how to use if statements to handle errors in our scripts. And so as an example, I've prepared an empty folder here. And in our script what we're going to do is try and cat out test. And since it's a folder, indeed, bash will complain to us and say it's a directory. But in an actual script, how can we handle this error and then do things accordingly if certain commands fail? So I'm gonna go ahead and open up this lesson 16 shell script. And let's write a function. I'm just going to call it try to cat folder. And it's going to be that same line test. And we can make use of a special variable. So similar to the dollar sign at variable, which meant all parameters passes function. There's another special variable in Bash which stores what's known as the error code of the previous command that was run. This special variable is the dollar sign question mark. And to have the most flexible script, the best way of evaluating this variable, checking if it's 0 or not. And we know from the previous lesson we can check this value with an if statement. And we just want to know if it's 0. So if it's 0, we'll say, actually we don't expect this one. Then else. We'll just say bash doesn't like it. When we tried to cut out a folder. And we'll close that. Well, we can source that and we're just going to call it. I don't need to pass any parameters. So we still actually get that output. But this is the result of our if statement and it says we expect bashed doesn't like it when we try to Canada folder. Now, you have to be careful with this special variable. It really is the error code of the previous command. So if you want to monitor the specific outcome of this command, we couldn't just write a command in, in-between. For example, I'll just say this echo will never fail. And now the dollar sign question special variable is relating to the error code of this statement, which will of course succeed. And then we'll enter this part of the if statement just to illustrate that. Going to source that again, and we'll rerun it. So actually the cat still throws the air because we're trying to cut out a directory. But because the special variable here now relates to the echo statement, it's successful and we're actually getting the nice we could cut out the folder, which isn't entirely true. So what's best to do here if you're monitoring specific parts or specific commands, is to store the variable immediately after the command. So for example, we can just call it error and assign it right there. And then we would reference that variable in the if statement and not the special variable itself. And if we run it again, we've successfully stored the air, not from the echo command, but the cat command. And now one thing I want to mention about this equals 0. That's probably the most universal way to check if a command through an error. And it depends widely on operating system and shell on what the error codes are. Typically all you can be a 100 percent sure of is if a command was successful, the error code will be 0. Otherwise it won't be 0. So for example, if we open up the man too Cat, and typically it's near the bottom, we'll provide an exit status. The cat utility exit 0 on success and greater than 0 if an error occurs. For example, if we look at the manual entry for a more advanced command like Grep, scroll down to the bottom. And we see here there are multiple entries for the exit status. So it'll be 0 when one or more lines were selected, which is basically successful, will be one when no ions were selected. Not really an error, but that'll be the specific error code. And if an actual error occurred, the exit status will be greater than one. And so returning to our script, if we want to get at this actual error code, we can simply echoed out here. Or perhaps better is at the end of the script. I'll just say can source that the error code is one. And if we override it here from the echo, we expect that the error code will be 0 because the echo command doesn't fail. So in this lesson, we learned how to process errors in our Bash scripts. We saw that we could use the special dollar sign question mark variable to access the exit code of whatever command was previously executed. And we also discussed how you have to be very careful with this command in that it really is only the previous command. And as soon as you run another command, its value will be overwritten. And so the best way to keep track of errors that occur is to immediately store the error right after running the command. Then you can check it and run conditional logic, for example, by checking if it's 0. We also saw how it's important to read the manual as some commands. For example, GREP have multiple exit codes. In the next lesson, we'll get into for loops and while loops in Bash. 18. All the Loops - Types of For Loops and While Loops: In this lesson, we're going to learn all about loops in batch, both for loops and while loops. So I'm gonna go ahead and open up this shell script or the lesson. And I mentioned a while back, we would have a bit of fun with this beep alias. And that was this guy where we're, what it is is echoing out the Unicode symbol or the bell. And that literally makes a beeping sound on the machine. And so to create a for-loop in Bash, it's similar to the if statement syntax. We've got these double parentheses. Then we declare what's due. I equals 0. I is less than or equal to, let's say five. And then I plus, plus. And instead of then the keyword here is du. And then whatever logic you want to run in your loop. And for us, we wanna do this beep. And then Done. Now if we source this, I believe it should run right away here. And hopefully you can all hear that we had five beeps in a row. So we can do a little bit better than this. Let's wrap this into a function and we can create more of a utility out of it. It's going to format that a little bit. And instead of a fixed 5 here, I'm going to pass in a variable. Rather this function will accept the variable and we can define the number of times that we want to be. So I'll source that. Now it doesn't run since it's living in a function, we have to call it. So I'll do B per three is less than or equal to. So it's, it's run four times. So this could be refactored to a less than. Let's try this. And that says we expect now to break out of a for-loop for whatever reason, we can use an if statement. And I'll just say, just to illustrate how to do this, we'll just say if I gets to three, then an important keyword here is break. And we can and that IF statement, source the script again. And so even if we pass, let's say 10, we should still only here three, because after three it'll break. Great. So that break is working. And just for completeness, we can write the same thing but as a while loop. And typically I don't use while loops. I think they're messy. And there's a common saying nowadays that whatever can be written as a while loop can also be written as a for-loop. I kind of agree with that. And for loops are much cleaner. But I will show you how to do the same in a while loop. And I'll just call it a beeper while. Also write a function. And so here we have to declare our variable outside the loop. And a similar syntax like the for loop, but we just have a simple logical compare here. And I'll do the same where we just want I to be less than the number of times we pass in. The same thing do we'll do VIP. And what we have to remember here is to increment the loop variable. So I'm using a little bit of variable evaluation here. This is the variable I plus 1, but then the whole thing evaluated as a number. And then just like the for loop done, can save that source that. And we'll do VBR while five. That works great. And we can do the same exact logic in a while loop to break out of it. And again, we'll source this. And even if I do beeper while five, we should only here three beeps. So while these may seem kind of like toy examples, this beeper function is actually one I have in my bash profile. And as I mentioned in a previous lesson, when you have a long running function or process, you can throw this at the end, for example, some process and then end and beeper. And I'll typically do anywhere from five or 10, depending on how many times I want the machine to beep. And when I hear that, then I know the job is done. So in this lesson we saw how to make for loops and while loops in bash. The syntax is similar to if statements. And we also saw that we could use the break keyword to break out of either a for or a while loop. If the specified criteria is met. 19. Environment Variables and the export Command: In this lesson, we're going to learn about environment variables using the export command. So far we've seen we can define local variables in a batch function. And let's hop into the lesson 18 shell script to set that up. So I'll just make a simple function, S. And I'll just call this myVar. Let's make it 1234. And we can echo out myVar. Now instead of sourcing this, I'm going to run a shell script as a sub-process, which is how you would normally run shell scripts. So far, we've always been sourcing the lesson shell script just so we could examine the variables and functions within me to actually add the call it tests so we can run it as a normal script. And when we run this as a normal script, it's going to call test. And hopefully we should see 1, 2, 3, 4 printed to the console. So to run that as an executable in a sub-process, we first need to change the file mode to an executable so that CH MOD. And then plus x, we're adding the Executable Mode and then the file name. Now the way to actually execute that is with dot slash and then the file name. And great, that's what we expected. And now because this variable is only in the scope of this function, we should expect that we can't get at that variable out here. And we see that there's nothing there. It's not set to 1, 2, 3, 4. But there is a way to set up environment wide variables, and that is with the export command. So we were to export my n var and 5678. And we see that the variables printed to the console. So while aliases and functions are more for commands and dynamic commands, using export is for storing values of variables. But they act in a similar way as aliases. For example. If we leave this terminal environment and try to echo my n var, it won't exist because it's not in the terminal environment. So just like aliases and custom functions, you also want to put export values in your bash profile or in a file that will run each time a new terminals open. And the special thing with exported variables is that they exist in your running processes. So for example, in node. Your process dot n, and this would be my n var. You could use that within a JavaScript file and it would have this value. So for development machines, these environment variables are nice place to save things like API keys and secrets. And you can access them in your processes. But note for a production environment, it's not the best practice to store such secrets in a bash profile. And you should use some sort of encryption service to store your secrets. Now, you can access all of your environment variables with the print f command and you would press Enter. But I'm not going to run that because this is my development machine and I have a lot of API secrets in it. And I don't want to show those on a similar note when you run into the infamous path issues along your development adventures. This is the same type of problem. There's usually something wrong with your path environment variable. So right now we can take a look at this path environment variable. Minds quite long. I have a lot of stuff built-in to the path. I have dotnet, I have some Android tools, my node, Google Cloud services. And if you're getting errors about something not found in the path or perhaps a command not being found. You typically have to add the correct path or directory into this path environment variable. And the easiest way to do that is, for example, if we make a test folder here, I've already created it. And we'll print the working directory because we want the full relative file path to append to the path variable. You can see that all of these different paths are separated by a colon. So you would just simply define the path new with the path that you want. We want this test folder with the colon and the existing path variable. And again, as we discussed, you wouldn't want to just run this in the console. This is something that belongs in your bash profile if you want to permanently add the missing command. So when this is in your bash profile, it'll be evaluated by bash every time. And the custom path that you've added will exist in your path anytime you open up a new terminal. So in this lesson, we learned about environment variables in Bash and how to set them up using the export command. And we discussed that they're analogous to custom aliases and functions, but they're not really commands themselves. The purpose of environment variables is to store actual values or actual variables. We discussed that you can print the entire environment with the print command, and that these variables would be available to you in any running process. For example, a node that is process dot, and then whatever name. In this example with the Mayan VD, that would be my n bar. We also talked about path issues that you can run into and how you could add a line similar to this in your bash profile to load in the correct directories. Though nowadays, most tools will automatically append that for you in your bash profile once you install them. 20. Bash Commands Part 9 - which and the --version flag: We're getting near the end of the course here. And the last few lessons are going to be about a few more commands. Then we'll have a sort of bonus fun lesson, and that'll be about it. So in the last lesson, we learned about environment variables. And at the end of the lesson, we discussed when you might have path issues. For example, if commands can't be found in your environment and kind of following that topic. Another command which is very useful in Bash is the which command. The which command will show you the location of the program file that you're using for whatever program you pass in. But for example, if I type in which Python, we can see that it's in usr local bin Python. This works for really anything. If I do, For example, my Node version. We can see that this one is in the NVM manager. I use nvm to manage my node versions, and it's in the binary folder. For example, if I switch to a different version of node, I also have 12, 21 installed. And if I say which node here, we can see that the version has switched to this folder, and this is all managed by MBM. And which will even work for packages which are installed under other programs. For example, Gatsby is a command line tool, but it's for node. In the case for 12, 21, which is an older version of node, I actually don't have Gatsby installed. So here, the which command returns nothing. And as we discussed in last lessons with path issues, this might be a hint that you really don't have it installed or wherever you have installed it. It's not included in the path environment variable. So if I switch back to a more recent version of node, I believe I have gets me installed here. And yes, we see that Gatsby is installed under the binary folder for this version of Node. So which is a good command that is kind of a sanity check to see if that command really is in your bath or if it's in the path it's supposed to be. Certain programs may expect certain binaries or other programs to be in specific folders. And you can use the which command to examine what folders those are. And continuing to follow this kind of system configuration and versioning discussion. Another very useful feature, and bash is actually not a command but a flag, and that is the dash, dash version flag. So nearly all command line tools implement this flag nowadays. And I actually opened up a question on Stack Overflow asking where this flag came from, if it was in the original Unix Specification or something like that. And unfortunately the question was closed for being too vague. And the best response I got was something along the lines of, well, it was never really an official part of any specification. But so many tools started implementing it and it eventually became a pseudo standard. So take that however you will. But anyway, with most commands, you can successfully pass this flag. So I'll even do it with Gatsby here that I'll print out the version, string and node. We would expect since we've just switched to 14.16, we would expect the same there. You can do it for Python. As I said, almost all command line tools implement some version of this flag. You may find with some tools, you can patch the shorter dash v. But I would say that's probably about 50 percent supported or less. I found the fall dash dash version is really the most reliable. And this flag, of course, is helpful in cases where you're working on a project and need to double-check your package versions to see if they're compatible or need to be upgraded. But it is just a simple command line check. I would always refer to whatever package manager you're using first. For example, MPM with node, or NuGet with C Sharp or pip with Python. So in this lesson, we quickly discussed the which command and the dash, dash version flag. The which command shows you the folder location or the file location on your system where that program is. And the version flag, at least for most command line tools, will print out the version of that program or binary that you're using. So in the next lesson we'll get into a few commands that are particularly useful for any developer dealing with open or listening ports. 21. Bash Commands Part 10 - lsof, process IDs, kill, killall: In this lesson, we're going to learn about the LS OF command. We're going to learn what process ideas are. And we're going to learn two powerful but sometimes dangerous commands, kill and kill all. So we'll start off with the LS OF command and Ls OF stands for list open files. And so alone. The ls command has a huge output. It's really any file being written to or read from at that moment. Again, it is a list of all the open files. Now quit out of there. With a few flags. We can turn LS OF into a great tool for any developer who works with listening ports. And what we can do is create a command that lists all open and listening ports on the system. And we'll be able to find out about the processes behind those listening ports. So if we go into the manual entry for LSO f, we're first going to scroll down to the eye, the dash I flag. This flag selects the listening of files whose Internet address matches the address specified. And so this doesn't have to be a specific address like a URL or something. These are all optional here and we can just pass even just a protocol. So we're going to pass the TCP protocol. So we'll be pre filtering that giant list we had by connections with the TCP protocol. And then we need one more. We're going to go down to the dash S flag. And we see that we have a P colon S optional form. And note that this form is available only for select dialogues. So far I've been able to use this form successfully on Mac and Linux. But you'll need to check if it will work on your operating system. But when this form is available, we can pass a protocol name for P and then a colon, and then a comma separated protocol stateName list. We don't need a list, we just want the listening ones. So there'll be dash S, TCP colon lesson. So let's craft that command now. So we said we wanted the pre filtered the listening files with TCP and their protocol. Then of those, we want the TCP listen State presenter to the much more readable list. It's actually quite small. We see I've got a memory cache listening, a Postgres instance. I've got another project running right now And actually this node process is the one from a few lessons back where I started up the process in the background with forever. And to double-check that, we can look at this column is the PID, which stands for a process ID. And this is 33 a12. And so if we call that forever list command, again, we see that the process ID is identical, so this is the same process ID. And now that we're into process IDs, we can cover two powerful commands that deal with process IDs. Those are kill and kill all. So I should mention that kill is a hard stop. That's basically like the control alt, delete, and then stop process on Windows, you will lose data if something important in the process is running. But for example, in this case, when you're running a dev server or something like that. And perhaps you've run into some sort of memory leak or an infinite loop and you want to kill that process, then I think it's safe to say on a development machine, it's safe to use kill or kilo. And so the kill command accepts the PID. So if we wanted to kill this specific node process, we will pass in this PID. If you had a bunch of node instances running and for some reason all of them were in a stuck stay or some sort of infinite loop or something like that. You will be able to pass kill all. And then the name of what program you want to kill. So would be killed all node. So just to illustrate the single-process, I'm going to kill this forever process. And there is no feedback. But if we go to list, we see that forever has done its job. The process was stopped. But what Forever does is if the process fails, it'll start up a new process. And that's where we see this new process ID. And we should expect if we run this command again, that node is now running under that process ID. And I should also mention on my system, I have this long command that's really hard to remember. I've alias that too. I call it which port. But perhaps, maybe listening ports makes more sense. And you could do something like that. You could add a line like that to your bash profile and then if you write listening ports, you get the same output. So a very helpful tool. Really, if you're a web developer, a front-end, back-end, building an API. It's really nice overview of all the listening ports on your system. Or if you're on a production server, you can double-check if your APIs or sites are actually running where you think they are. The LS OF cannot lie. So it will really show you what ports and what processes are running on them. 22. Bash Commands Part 11 - chmod: We're nearing the end of the course. This lesson, we'll cover the last command for this course, and it's an important one. It is CH MOD. We saw it already though briefly to make shell scripts executable. So for example, the current lesson script is not executable. If we try to execute it, bash will yell at us saying that we don't have permission. We saw that we can make it executable by running CH MOD plus x on the file. Now if we try to execute, it, should work. Right now there's nothing but comments in that file. So nothing's actually happening. But at least bash doesn't complain that the permission is denied. But what's really going on here? You may have noticed when we run ls dash l or my preferred LK alias, in the first column of every file or folder, we have these strange looking strings. These are the file permissions. For folders. We have this little d here, but for each, we have these nine characters. The nine characters represent three possible permissions for three groups. And so the groups are these three for the owner. These three for the group. And these three for everyone else, or in Unix known as others. I should also mention these user permissions correspond to this user, which is me, Chris. And these group permissions corresponds to this group, which is staff. There's nothing listed for others, because others literally means the public or anybody out in the world. So there's no name assigned to it. So the actual permissions for each group are the same in their notation. We have r for read, w for write, and x for execute. If that user group or other does not have that permission, then there's simply just a dash. So using the CH MOD command, we can change permissions of this group using what is known as the symbolic notation, which is this notation here. And we saw that we could add executable across the board. We see here for this lesson, the executable has been added for the user, the group, and others. And we can remove that similarly with a minus x and pass the file. Now if we take a look, the execute permission has been removed from all three groups. And we can do more complex manipulations using CH MOD and symbolic notation. For example, let's do something crazy like taking both the user and group. And we want to add execute, read, and write. And then for others, we want to add right permission. And we pass in the file again. Take a look there. Perhaps I've got a typo and that's been added. So now we see that the user has read, write and execute. The group has read, write and execute, and the others have read and write. But we can see with this notation that it quickly gets messy and it's kind of hard to see exactly what we're doing. And even with the plus x permission, we've kind of made a mistake there and that we've made the file executable for all groups, including any public or outside accessor, which probably isn't the best thing to do. So typically what's used in documentation and other things you'll see around the web. And other projects is what's known as octal notation. And octal notation is simply a shorthand for this symbolic notation that we've been working with its base eight, since there are only three options. And each number 0 through eight describes what combination of permissions are allowed. So in the lesson shell script, I've listed out what each mean. And so 0 is no permission. One is execute, only, two is right, only three executing, right, for read-only five executing read, six, read and write. And seven is execute read and write. So if this is looking a little bit overwhelming at first, what I typically do is head to this site, which has a nice interactive UI. And so you can play around with the different permissions. And for example, if we create a fresh file, I'm just going to call it file.txt. Let's take a look at what permissions are given by default, and we can try and recreate it in that UI. So we've got the user having read and write, the group having read only and the user having read-only. So let's see if we can recreate that here. So he said, owner has read and write. The group is read only and the public only has read as well. So yep, we've got the symbolic string there. And this GUI shows alongside of the symbolic notation, octal notation. And this 644 is typically the default on most Unix or a Unix-like operating systems when you make a new file. And it's a fairly common sense policy, only the owner of the file can write to it and then the group or others can only read it. And as a default, nobody can execute it. So we've seen that by default with commands like ls, files and folders are listed in the symbolic notation. On a Mac, we can list the permissions for file.txt, for example, in octal mode with the following command. Just stat dash f percent a and file.txt. And we see we have that 64 for which corresponds to this permission string. On Linux, it's a bit different. Would be something like this. In addition to setting permissions using the symbolic notation which we've seen, you can of course, use the octal syntax to set permissions. And in my opinion, it's the easiest way and most concise way to granularly modify what permissions you want. Instead of adding plus x, which would add executable permissions across the board for a file. Let's make it executable only for us, the user. So I'm going to do CH MOD. We'll do seven. We want read, write and execute for us. And then those default for, for, for, for the group. And four for the user, which is read-only. And I'll issue that on Lesson 21 shell script. Now if we check their great, That's actually exactly what we want. Actually, in my opinion, is better than just the plus x operation. So we've made it executable for ourselves. We can execute that. No issues. But it's not executable for the group or the user anymore. So CH MOD also has the dash R flag, like we saw with grep and a few other commands. And that means recursively change the permissions of all files and folders under the path that you specify. And sometimes on Stack Overflow, you'll see the infamous CH MOD dash r 777. And this is 99.9% of the time. Poor or incorrect advice. In the problem with that command is that it's potentially making all those files and folders in the path you specify accessible by any user. So not just readable, but also writable and executable. So that can be potentially very dangerous. So I just want to say that Unix systems have advanced permissions for a reason. And it's one of the reasons among many whites so hard to write viruses and other exploits on them. So permission problems are definitely something that you will encounter. But typically the quick fix solution of setting the permissions to 777 is incorrect. Usually it involves carefully reading the documentation of whatever program or framework you're working with, and following that documentation carefully and implementing the permission system that they recommend. So in this lesson, we learned all about C-H MOD or change mode. And we saw that typically files and folders are listed using the symbolic notation. And we learned about the shorthand octal notation. And I've summarized what the octal notation actually means. And we looked at this neat GUI, which you can find online and play with the different permissions for each of the three groups. And we saw that you could use the Change Mode command using both the symbolic notation, for example, adding executable functionality, or using the octal notation. For example, if we wanted to add executable functionality for the user only, and we wanted to keep the group and user permissions as the default. 23. BONUS: Change and Style Your Bash Prompt: So save the best for last, right? Or at least the most fun. In an earlier lesson, I said that we'd get into how to change this prompt right here. And in this lesson. And that's exactly what we're gonna do. So first off, we're going to hop right into the bash terminal. I'm going to use my probe alias and hop right in there. So in bash, the prompt itself is actually reserved in a variable, and this variable is PS1. We can see here from my current prompt, I've already got a lot going on. So first off, I've defined these color variables. And these special strings tell bash to start formatting text in a certain color. So I've got red, green, yellow, blue, magenta, cyan, and white. And they're a bit ugly and hard to read. So that's why I've stored them as short variables. And basically bash will continue formatting, reading left to right. It will continue formatting in the given color until it encounters a new color string, one of these or this end formatting command. And when we're in the PS1 string, there are some other characters that also have special values, and I mentioned those earlier in the lesson. But basically to get the user, it's slash you, to get the host is slash H and the current directory is slash w. But I like mine wrapped in square brackets. And I also always add the end formatting or else the colors will carry on into the command line. But perhaps that's what you want. So I'm gonna do is source the bash profile. And this is my standard so user at host. And then the directory within the square brackets and then a space. So for example, maybe you do want the colors to carry on into the command line. You could take away that end of color formatting will source the profile again. That's using my alias. And hello, I am blue. And you can even pass a different color. For example, if we want to make it, let's make it cyan. Just taking this variable up here. Source that That's how you can get different colors right in the editable part of the prompt itself. Going to revert this back to what I had. And we can comment this out. I've prepared this one. I call it The Star-Spangled directory prompt. A bit corny, don't make fun of me. But just red, white, blue, and then the directory is white and the text will be white. If you're a minimalist, you could have a totally empty prompt. I don't know. I think it's a bit weird. You can enter commands. I think it's kind of hard to follow, but maybe if you're making a cool video or something, it might be useful. So that's empty prompt. And you can even put in emojis. So you want this cool rocket source, the profile, There's our rocket. And you can have that will, will developer guy could be, could be me. And at laptop. Very cool. And I've also prepared using a slightly different scheme for single letters. I've prepared this crazy alternating letter color prompt. I source that gets something like that taken rocket and stars and I've called the intergalactic Mac. I'll comment that out now. And as one final bonus, there is another built-in variable called prompt command. And if this is actually set right now I've left it empty for this lesson. But when it's set, you can set it to a function and bash, we'll run it after every command you enter in a terminal. And so I've prepared here this smile a prompt function. And it's what we learned from both our if statement and error handling lessons. And what I do is check if there was an error or not. If there was no error, will append a smiley, a green smiley to the PS1 variable. Otherwise we're appending a red frowny. And so let me just set that function to this reserved variable. We'll source this again. And so we know an echo will never fail. But for example, anything else really any non-existent command. Bash is complaining command not found, and we have our frowny face. So that's just a little look into the customizable abilities of the prompt. And you can really spend a lot of time and have a lot of fun with this. So go ahead and try and make your own, make your own unique prompt. I think one of the most fun parts of being a developer is customizing visual things like that at your own workstation to how you'd like them. So have fun. So just to cover what we went over in this lesson, we learned that the reserved variable or the prompt itself is in this PS1 variable. And we saw how we could format that with the special characters which represent the user, the host, and the current directory. And we then saw that there's another reserved variable called the prompt underscore command. And we could assign a function to that in this variable is telling bash to run this function every time we enter a command. And so that was the last terminal lesson for this course. And hope you stick around for the short outro. 24. Outro: So that was my course, bash commands and scripting from beginner to expert. I hope you enjoyed and I hope you learned a lot. As always, if you're stuck or have questions, comments, critiques, anything, leave a comment in the relevant lesson, or reach out to me by email and I'll get back to you as soon as I can. That's it. Enjoy your Bash scripting and until next time.