Become a bash scripting pro - full course — Transcript
Full transcript
- 0:00hey folks so in this video I want to
- 0:02teach you the superpower that is Bash
- 0:05scripting and a superpower it is it's
- 0:08one of those things that you can pick up
- 0:10really quickly as you'll see here I'm
- 0:12going to teach you virtually everything
- 0:14that you'll need to know to write any
- 0:16script that you'll ever write and once
- 0:17you get in the habit of writing bash
- 0:19scripts it's one of those things that is
- 0:21a real Force multiplier things that you
- 0:23would do manually often and you just
- 0:25deal with are things that you can
- 0:27automate very easily in a matter of
- 0:29minutes and you'll never have to do
- 0:31manually again so let's walk through it
- 0:34so I've written a lot of bash scripts
- 0:35over the years I've tried to gather all
- 0:38of the knowledge that I've gained and
- 0:40extract essentially everything that I
- 0:43know that you need to know to write
- 0:45virtually every script that I've written
- 0:47and none of the weird things that you're
- 0:48not going to need to know because there
- 0:50are weirdnesses in the language but you
- 0:53really don't need to deal with them the
- 0:55majority of the time so let's get right
- 0:57into it it does build on a knowledge of
- 0:59the shell and how to actually use bash
- 1:02so if you're not familiar with the
- 1:03command line and all that I did put out
- 1:04a video a couple weeks ago that you can
- 1:06check out to refresh your knowledge or
- 1:08or learn for the first time otherwise
- 1:11let's check it out so to create a bash
- 1:14script it's just a file like anything
- 1:16else typically it'll have the sh
- 1:18extension so got this hello.sh here so
- 1:22the first line should always be the
- 1:23shebang it's a fun word but what it is
- 1:27is a way for you to tell your shell what
- 1:30interpreter to use for this script so
- 1:32here we've got and this is a comment so
- 1:34it starts with a hash and you do an
- 1:37exclamation point or a bang and then you
- 1:39give it the path to your interpreter in
- 1:42this case we're using bash a good
- 1:43practice is to use this user bin EnV and
- 1:46then passing the argument of The
- 1:48Interpreter so in this case bash and
- 1:50what this EnV tool does is it'll check
- 1:53in your system where the correct
- 1:54location of bash is and we'll talk about
- 1:57how the path Works in a bit but suffice
- 1:59to say this will make sure that it's
- 2:01running the correct instance of bash for
- 2:04your system a common problem that you'll
- 2:06see is people do something like this
- 2:07where it's hardcoded the path of Bin
- 2:10bash but that's not portable some
- 2:12systems like mine for instance like I
- 2:14don't have bash in that path and so if I
- 2:17try to run a script that has been bash
- 2:20declared it's going to fail out
- 2:21instantly so that's no good so bash you
- 2:24know being a shell language is very
- 2:26command focused and this is what makes
- 2:29it so easy to work with anything that
- 2:31you've run on your command line you can
- 2:34run directly the same exact way inside
- 2:36of the script so Echo hello YouTube you
- 2:39could do that in your command line you
- 2:41can do that exactly the same here you
- 2:43got your command space and your argument
- 2:46it has access to all of the same things
- 2:48that you have in your system so I can
- 2:50run G settings which is a gome utility
- 2:52for setting things in the desktop
- 2:55manager so you can set the color scheme
- 2:57for instance again you can also do
- 2:59things like
- 3:00pipelines so we can do this Cube control
- 3:02command which passes into the fuzzy
- 3:04finder ax some stuff and eventually runs
- 3:07through and does a cube control describe
- 3:09against the pod that's a long command
- 3:12and that's something that now by virtue
- 3:14of having an A bash script you don't
- 3:16ever need to remember how to write it
- 3:18out manually you can just refer to the
- 3:20script that's the real power of this you
- 3:22know we've learned one feature which is
- 3:24calling commands and even with just that
- 3:27even if there's nothing else you can
- 3:28still get gr value out of using this
- 3:31because you can take any series of
- 3:33commands that you'd run and now self
- 3:35enclose them into a single script but
- 3:38there's a lot more to the language so
- 3:40let's check it out but first if we go
- 3:42back to our simple example of just an
- 3:44echo statement if we try to run the
- 3:46script we're going to run into some
- 3:47problems that's where we need to learn a
- 3:49little bit about permissions on unic
- 3:51systems so if you run this hello.sh
- 3:54script and to run it you give it the
- 3:55file path we're doing slash because it's
- 3:57in the current directory you're going to
- 4:00see this error which says permission
- 4:02denied if we run LSL we can see the
- 4:05permissions on this file and this is
- 4:07going to be true for any type of Unix
- 4:09system so if it's Linux or Mac you're
- 4:11going to see this where we have these
- 4:12file permissions set for the user for
- 4:15the group and for everyone else in this
- 4:17case we've got read and write
- 4:19permissions for the user and we just
- 4:21have read permissions for the group and
- 4:23for everyone else and that's why we have
- 4:26this error because we don't have execute
- 4:28permissions so to remedy this situation
- 4:30we can run chod which is a command line
- 4:33utility that allows you to change the
- 4:35file permissions on a file so here we
- 4:38have + x which is saying for the user
- 4:41add the execute permissions for this
- 4:43given file then if we run ls- L again
- 4:46you can see now for the user they do
- 4:49have read write and execute but the
- 4:51group and the others still don't if you
- 4:53did want execute permissions for
- 4:55everyone you could do just chod plus X
- 4:58but just calling the principle of least
- 5:00privilege it's always best to default to
- 5:03just doing the user and opening it up
- 5:05beyond that if needed but with that in
- 5:08place now we can run the script and
- 5:10it'll run as we'd expect but everything
- 5:12so far has been static one of the powers
- 5:14of actually using a language is you can
- 5:17parameterize things so let's pull out
- 5:19the name YouTube into a variable so a
- 5:22variable in bash isn't going to be
- 5:24defined with let or const or VAR
- 5:27anything like that it's just the name of
- 5:29the variable in this case name and then
- 5:31equals and this is important you can't
- 5:34have spaces around the equal sign here
- 5:36so it's has to be name equals YouTube if
- 5:39you did try to do something like this
- 5:41where you have spaces around the equal
- 5:42sign because bash being a command first
- 5:45language it's going to see this and
- 5:47think another is a command and you're
- 5:49passing an equal sign and universe as
- 5:52arguments but of course another isn't a
- 5:54command and that wasn't what we intended
- 5:56so that's an error to actually reference
- 5:59the variable you just do dollar sign and
- 6:01then variable name and that'll be able
- 6:04to print out just the same as we had
- 6:05before if you do single quotes instead
- 6:08of double quotes that doesn't do the
- 6:10variable expansion and so that'll print
- 6:12out the literal characters you dollar
- 6:15sign name instead of expanding to the
- 6:17value of the variable so watch out for
- 6:19that there's also this format with the
- 6:22curly braces so dollar sign curly braces
- 6:25variable and we'll see that this has
- 6:27some nice properties so you can add
- 6:30additional operations against it like if
- 6:32you put a hash in front of the variable
- 6:34name instead of printing out the value
- 6:37of the variable it's going to give you
- 6:38the length of the value in this case U2
- 6:41being seven characters it prints out
- 6:44seven in the place of the variable a
- 6:46common situation you'll have is you'll
- 6:48have a variable that is undefined and
- 6:50you're trying to reference it but if it
- 6:53doesn't exist well you're going to get a
- 6:54blank slot so instead you can set this
- 6:57default value and the syntax looks like
- 6:59this where it's within the curly braces
- 7:02and you do variable Name colon dash and
- 7:06then the value in this case we have
- 7:08Anonymous so with name being equal to
- 7:11nothing when it gets to this spot it's
- 7:12going to see okay name is not said so we
- 7:15use the default value though it's
- 7:17important to know with this particular
- 7:18version if we do Echo name after that
- 7:21it's going to be blank again because
- 7:23name is still empty we just used the
- 7:25default value in that slot however if
- 7:28you want to also set the value to the
- 7:30default you can use an equal sign
- 7:31instead so now it'll print out Anonymous
- 7:34as the name on line five there next up
- 7:37let's take a look at the subshell the
- 7:40subshell is something that you'll end up
- 7:41using a lot so the way it works is like
- 7:44this you've got a set of parentheses and
- 7:47within the parentheses you'll have some
- 7:50operation let's take a look at an
- 7:52example so if I was to run PWD to get my
- 7:55current directory it'll print out that
- 7:57I'm in The Bash directory but then if I
- 8:00run a command in the subshell where I
- 8:03first CD to The Parent Directory and
- 8:05then run PWD you can see I'm in the
- 8:07videos directory but if I then run PWD
- 8:10again from the original shell we're
- 8:12going to see we're still in the bash
- 8:14directory that's because the CD and any
- 8:16operation within that subshell was just
- 8:18in the context of that subshell it
- 8:20didn't impact what's actually going on
- 8:22in my current shell that becomes very
- 8:25handy in many use cases but most
- 8:28commonly you're going to use it for
- 8:29command substitution which looks like
- 8:31this where you have a dollar sign and
- 8:33then parentheses so you can run your
- 8:35command from within the subshell and
- 8:37then you can use that anywhere that
- 8:38you'd use a value here we're using it in
- 8:40a variable assignment and we can then
- 8:43use that value anywhere that we want
- 8:45here's a more interesting example where
- 8:47we're first fetching from an API a Json
- 8:50response and then we're using JQ to
- 8:53extract a value from that and the way
- 8:55that these subshells work with this
- 8:56command substitution is it takes the
- 8:58final out outp put so image URL will
- 9:01just be the literal URL that we get from
- 9:04this JQ command and then we can use that
- 9:06in the next step to curl from that URL
- 9:09there's also this thing called process
- 9:11substitution where you're able to treat
- 9:13the output of a command like a file so
- 9:15in this case we're using the diff tool
- 9:17which is expecting two different files
- 9:19to be passed in and using the less than
- 9:22and then parentheses syntax you just run
- 9:24a command and the output of that is
- 9:26going to be treated as a file so we're
- 9:28going to be comparing the difference
- 9:30between these two Ls outputs as if they
- 9:32were files there's also the arithmetic
- 9:35expansion so got this dollar sign and
- 9:37then double parenthesis that's where you
- 9:39can actually run any mathematical
- 9:41operations and it might be surprising to
- 9:43you if you've never tried but if you run
- 9:453 + 4 within the shell it's going to say
- 9:48something like in this case three is not
- 9:50a command and so it has to be within
- 9:52this block in most bash scripts you
- 9:54write you're going to need some form of
- 9:55user input and that often comes in the
- 9:57format of command command line arguments
- 10:00so for instance in the script that I
- 10:02have here where I'm merging a video file
- 10:04in an audio file into a single output
- 10:07I'm calling the merge AV command that's
- 10:09going to be assigned to the zero
- 10:11variable the first command line argument
- 10:13is going to be the variable one second
- 10:15one to two and so on so then from within
- 10:17the script what I like to do and I think
- 10:19this is a very good practice is to
- 10:21create these intermediary variables so
- 10:23I've got video input is equal to the
- 10:25variable one audio input to two and so
- 10:28on and then you just use those
- 10:29throughout your script you could if you
- 10:31wanted to just directly use 1 two and
- 10:33three but if you compare the clarity of
- 10:36the top and the bottom here I think it's
- 10:38much clearer what those variables
- 10:40actually refer to in the top another big
- 10:43part of men script is going to be
- 10:44conditional logic and that's where if
- 10:46statements come in so if statements the
- 10:48actual structure is pretty simple so
- 10:51it's if some condition is true then do
- 10:54this top block L if so if some other
- 10:57condition is true but not the the first
- 10:59one then this will be performed
- 11:01otherwise we'll do this final one in the
- 11:03else and we close it out with an fi
- 11:05which is just reversed if so all fairly
- 11:09conventional if you're wondering why
- 11:11there's like a semicolon and then then
- 11:12on the same line you could do it on
- 11:14separate lines if you wanted to you
- 11:15could do if then like this personally I
- 11:17think the second form here is kind of
- 11:19ugly there is one element of Bash that's
- 11:21a little bit strange again being a shell
- 11:24first language this is probably why this
- 11:26is the way that it is but in other
- 11:28languages like if you look at python or
- 11:29JavaScript there's a concept of
- 11:32truthiness where if you compare 1 is
- 11:34equal to one the result is going to be
- 11:36true if you compare 1 to two it's going
- 11:38to be false well that's not the way that
- 11:40it works in bash it uses exit codes
- 11:42where the exit code of zero is a success
- 11:45an exit code of literally anything else
- 11:48whether it be 1 10 200 it doesn't matter
- 11:51that's going to be a failure the
- 11:52specific number that an exit code has
- 11:55Beyond just meaning that it's a failure
- 11:56doesn't generally mean anything now a
- 11:59specific command or a specific script
- 12:01can choose specific numbers and then you
- 12:03can do specific error handling based on
- 12:06that number but most of the time you'll
- 12:08just do something like this where you've
- 12:09got an if block you know so if some
- 12:12condition if something failed then Echo
- 12:14you know do your logging but then exit
- 12:16one and that's going to say all right
- 12:18stop the program here but we're
- 12:20returning to whoever kicked this off
- 12:21that this was in fact a failure so what
- 12:24this means with this exit code approach
- 12:26is that you can run commands as
- 12:29conditionals so here we've got an
- 12:30example with grep where we're searching
- 12:33a logs. text file for any occurrence of
- 12:35error and if there's a match that's
- 12:37going to be a success that'll return
- 12:39exit Code Zero and then we're going to
- 12:41do what's in the first block here
- 12:42otherwise if there are no matches it's
- 12:45going to return the else block all is
- 12:48fine in the world now it probably feels
- 12:50a little bit weird in this example
- 12:51because you'd think that well we have
- 12:53errors in our logs. text surely that's
- 12:55not a good thing but you got to remember
- 12:57it's in the context of GP trying to
- 13:00search for a match the match itself is
- 13:02the success state so that's why that is
- 13:04how it is but most of the time you don't
- 13:06need to worry about that most of the
- 13:08time you'll be doing conditionals and
- 13:10Bash has a lot of conditionals so the
- 13:12built-in conditionals use this testing
- 13:15syntax which has this double square
- 13:16brackets and it kind of uses a
- 13:19command-like syntax where you need to
- 13:20have spaces around everything if you
- 13:22have everything squished up it's going
- 13:24to be a syntax error so make sure there
- 13:26are spaces again your editor should warn
- 13:28you about that but we can see we have
- 13:30things like string comparisons you're
- 13:32used to like the double equals or not
- 13:34equals but for numerical comparisons you
- 13:37have to use these short codes of- EQ or-
- 13:41NE and so on you also have ones like
- 13:43this for variable existence so you can
- 13:45do- Z to see if something is empty or
- 13:48dasn to see if it's not you can do file
- 13:50checks to see if things exist you can
- 13:51check what the permissions are and you
- 13:53can also combine them so you can do d a
- 13:56or- o for logical and or or or can also
- 14:00do it externally with the double Amper
- 14:02sand or the double pipe for the and or
- 14:05the or my preference is to use the
- 14:07external because it makes more clarity
- 14:09in my mind as to where the separations
- 14:11are you can do internal if you like as
- 14:13well okay we've been talking language
- 14:16specifics for a little bit I just want
- 14:17to show off a couple useful commands
- 14:19that you're going to want in a lot of
- 14:21scripts that you write so first is sleep
- 14:24probably familiar with this you can just
- 14:26say how many seconds you want to sleep
- 14:27for and it's as simple as that we'll see
- 14:29an example of this later on there's also
- 14:31the read command for getting user input
- 14:34throughout your script so you can do
- 14:35something simple like this where we're
- 14:37asking for the user's name and the
- 14:40command is just read and you can pass in
- 14:42the variable that you want to assign the
- 14:44output to so if I run the script what is
- 14:47your name give it my name and then it'll
- 14:49use that as the variable that it's
- 14:51printing out more often than not the way
- 14:54that I use this is for approvals or
- 14:56input steps where something is happened
- 14:59and you want to make sure that the user
- 15:00wants to proceed from this point and so
- 15:02you can do something like this where you
- 15:04say do you want to continue if they
- 15:05don't say yes you can exit out probably
- 15:07want to have a little bit more Nuance to
- 15:10it than this simple example but this
- 15:12kind of idea is very common back to bash
- 15:15specifics as I've mentioned before bash
- 15:17is a strange language and I want to talk
- 15:20a bit about the behavior and how we can
- 15:22make it a little bit more pleasant to
- 15:24work with so if you're familiar with
- 15:26JavaScript or Pearl you might be aware
- 15:28that there's a strict mode with those
- 15:30languages but the idea is you can make
- 15:32things a bit more strict so you're more
- 15:34likely to encounter errors to make your
- 15:37code better there's this command that is
- 15:39often called the strict mode of bash
- 15:42which is this set- euo pipe fail which
- 15:46is a combination of these three commands
- 15:48that set some different behaviors so
- 15:50let's walk through this just so we can
- 15:51understand what's going on so if you
- 15:53don't have set- e what happens is a very
- 15:56weird Behavior so the false command here
- 15:59is just going to be a failure it should
- 16:01exit the program or that's what you'd
- 16:03expect but with bash when something
- 16:06fails the script just keeps on going
- 16:08which is not good behavior so that's
- 16:11what set- e resolves if we run false
- 16:14again the program will just exit
- 16:16immediately it's not going to continue
- 16:17on to the next step that's good because
- 16:19typically in an imperative language
- 16:22you're going to expect that everything
- 16:23is going to be building on top of each
- 16:25other so if one thing is failed you
- 16:26really don't want the next step to
- 16:28proceed because you're at that point
- 16:30expecting that the previous things have
- 16:31succeeded so I would always use this
- 16:35though as an aside there is this thing
- 16:37called conditional execution where you
- 16:39can say command one and then double
- 16:41Amper sand command two where it'll say
- 16:44if command one succeeds then run command
- 16:48two or you can opt for if command one
- 16:51fails then run command two but if
- 16:53command one succeeds then just skip
- 16:55command two Al together these can to be
- 16:57very handy in the these situations where
- 16:59we for whatever reason couldn't use set-
- 17:01e for a command like false which will
- 17:03fail we can use the or the double pipe
- 17:07and just say exit one so if that fails
- 17:11then we'll immediately exit the program
- 17:13as we'd expect but better is to use set-
- 17:16e and then in this case if we have a
- 17:18command like false which we know is
- 17:19going to fail but we want the program to
- 17:21continue anyway we can do this where we
- 17:24or that with true so if false encounters
- 17:27an issue then we'll run true and true is
- 17:29going to be a success so it'll carry on
- 17:32so without set- youu you'll often
- 17:34encounter this problem where you
- 17:36reference a variable like name in this
- 17:38case where name was never actually
- 17:40defined and the result is it'll just
- 17:43print nothing in that spot but the
- 17:45script will continue on but the reality
- 17:47is you probably because you referenced
- 17:49it you probably wanted name to exist you
- 17:51were hoping that something was there and
- 17:53so if you do set- U this will have it so
- 17:57it exits on the case of referencing
- 17:59something that's undefined at that point
- 18:01so this will help you catch a lot of
- 18:03minor bugs where either you typo
- 18:05something or you thought that you
- 18:06declared something up above and you
- 18:08didn't always good to have and then set-
- 18:11o pipe fail we're going to use set- e
- 18:13with this to make this easier to
- 18:16understand if you run something like
- 18:17false which again fails and then you
- 18:19have that as part of a pipeline where
- 18:21the next step runs and that succeeds the
- 18:25false at the beginning the failure
- 18:26actually gets lost and so even though we
- 18:28have set- e and the program should exit
- 18:30when something fails it's going to
- 18:32continue on anyway cuz it's how the echo
- 18:34hello was a success whereas if we
- 18:36introduce the- o pipe fail it will
- 18:39detect that first error the false where
- 18:42it fails and then the script itself will
- 18:45exit that's again much better Behavior
- 18:48you don't want to lose errors in a
- 18:50pipeline so in general I would always
- 18:53add this set- EO pipe fail right below
- 18:56your shebang all right all right so at
- 18:58this point we've actually covered
- 19:00probably 80% of everything that you're
- 19:01going to need to know but as I mentioned
- 19:03there's a lot of the language that I've
- 19:05never even used and I've written a ton
- 19:06of bash scripts so I'm going to show you
- 19:08the things that you're likely to
- 19:09encounter at some point probably not in
- 19:11every script but in some so arrays
- 19:15sometimes you need to create a list of
- 19:16items so in this case I'm creating an
- 19:19array of numbers and the syntax honestly
- 19:21a little bit confusing so it looks like
- 19:23a subshell but it's not when you do the
- 19:25variable assignment with the parentheses
- 19:27here each item and it needs to be
- 19:29separated by spaces but these are going
- 19:31to be separate items in the array and
- 19:33then to access them if you want to
- 19:35access a particular item in that array
- 19:37you can use the index like this where we
- 19:39have the square brackets and the index
- 19:41number you can also refer to all the
- 19:43elements if you're doing the square
- 19:45brackets if you do the at sign that's
- 19:48going to reference all of them or you
- 19:49could just leave off the square brackets
- 19:51and just do my array and that would also
- 19:53work and again we can do other things
- 19:56like using the hash to print out the
- 19:58length of the array so the number of
- 20:00items we've also got four Loops which
- 20:03bash actually has a surprisingly good
- 20:05variety of four Loops here so you've got
- 20:07a pretty standard one here where we've
- 20:08got four item in my array and so this
- 20:11will Loop through each element from my
- 20:13array here and you'll see the syntax
- 20:15here is do and done so everything within
- 20:18that block will be done for each item
- 20:20there we go as expected it just prints
- 20:22out the numbers but it also has a cstyle
- 20:25version so you can do the classic I
- 20:27equal Z I is less than whatever i++ you
- 20:31can do things like that a more compact
- 20:33version is with the range so 4 I and and
- 20:36you can say I dot dot whatever number
- 20:38you want so here's an interesting one
- 20:40where you can do pattern matching so you
- 20:42can set a pattern like this where I'm
- 20:44looking at all of the markdown files
- 20:46within the content directory we've also
- 20:48got command results so you can run
- 20:50something like LS which will return a
- 20:52list of items and then we'll Loop
- 20:54through each item in that output so a
- 20:57pretty good r iy there of course there
- 20:59are also while Loops I don't find myself
- 21:01using these all that often but the
- 21:03syntax is pretty straightforward while
- 21:05condition do done one little Oddity here
- 21:08is again due to the weird way that math
- 21:10Works in bash to increment the counter
- 21:13here you need to do it in those double
- 21:15parentheses but we get the same result
- 21:17as we'd expect now the one use case that
- 21:19I do find myself using while Loops for
- 21:21quite a bit is for what I call wait
- 21:23until true so in this case I'm going
- 21:25through an example where I deploy some
- 21:27application to kubernetes cluster and I
- 21:29wait until it's up into a running state
- 21:31so we've got an infinite Loop here so
- 21:33while true do the following and so first
- 21:36we'll save some status so in this case
- 21:38I'm getting the Pod status in a subshell
- 21:41and we're getting that output it'll look
- 21:43something like starting up or running or
- 21:46whatever in this case I'm waiting till
- 21:48the status is equal to running and as
- 21:51soon as that matches I'm going to break
- 21:52out of the infinite Loop otherwise we'll
- 21:55go into this else block and it'll print
- 21:57out some logging statement and then
- 21:59it'll bring back that sleep that we
- 22:01talked about earlier all right another
- 22:03situation you'll encounter at some point
- 22:04if you're writing a long script is that
- 22:06things get a bit complicated to
- 22:08understand you know it's just not
- 22:09pleasant to work with so you can break
- 22:11it out into multiple files now should be
- 22:14noted that bash has no concept of
- 22:16namespacing or modules or anything like
- 22:18that it's just separate files and so
- 22:21here we've got a setup here where we've
- 22:23got this provisioner Dosh which will
- 22:25pretend is provisioning some new vir
- 22:28machine and then it's going to configure
- 22:30some DNS records and so on so we've got
- 22:32an instance. sh which will handle the
- 22:34provisioning of the virtual machine got
- 22:36the DNS file that will actually update
- 22:39the DNS records and the provisioner dosh
- 22:42will kick off each of those in their
- 22:44turn so calling out to those different
- 22:46scripts as we can see is just like
- 22:48running any other command except we're
- 22:51doing it as a relative path rather than
- 22:53a command but just like anything else
- 22:56from the command line we can pass
- 22:58arguments right so we could in each of
- 23:00these scripts have the relevant
- 23:03variables for those like the region and
- 23:05the size for the instance and the domain
- 23:07name for the DNS but there are two ways
- 23:09of actually doing this so you can Source
- 23:12a shell script or you can kick it off
- 23:14execute it in a subshell so sourcing is
- 23:17kind of interesting where it's going to
- 23:20operate in the same shell so here's an
- 23:22example of how this works so if I set my
- 23:24favorite color is equal to green and
- 23:26then I Echo that we can see the output
- 23:27is green then I Source it using this Dot
- 23:31and then the script with the space in
- 23:33between there that's saying Source this
- 23:35script that will load it up and so now
- 23:38when we Echo favorite color it's still
- 23:40green then if I set favorite color to
- 23:43blue and then Echo that we get blue but
- 23:45then back in script one if I Echo
- 23:47favorite color we get blue and that's
- 23:49because if we think about how the source
- 23:51will work it's effectively taking all
- 23:54the contents of script 2 and just
- 23:56dumping them in line into script script
- 23:58one exactly where the call to script 2
- 24:01is so that means that we're using the
- 24:03same shell all the variables are the
- 24:05same and it's all just a way of breaking
- 24:08things out so that makes it easy to
- 24:10carry on all the continuity with
- 24:13everything without having to pass around
- 24:14values so in some cases this is quite
- 24:16handy the other way is the subshell
- 24:18where if we do favorite color is green
- 24:21once I call it to script two without
- 24:23using the source this is just executing
- 24:25the script this now spins up in a
- 24:27subshell
- 24:28and when it runs Echo favorite color it
- 24:30actually has no idea what favorite color
- 24:31is cuz it hasn't been declared yet and
- 24:33if we had set- set it would have exited
- 24:36the program because it would say hey we
- 24:38have no idea what this is but once I
- 24:40declare favorite colors blue and print
- 24:41that it's cool with that and then back
- 24:43to script one favorite color as far as
- 24:46its wear is still green so we can see
- 24:48those operate very differently so the
- 24:50question is which one should you be
- 24:52using and it really comes down to both
- 24:54personal preference and the specific use
- 24:56case I like to default to using the
- 24:58subshell version because I don't like to
- 25:01have all these implicit references
- 25:03everywhere I would prefer to pass in
- 25:05exactly what a script needs just like
- 25:07with functions you don't want to be
- 25:08referencing Global variables you really
- 25:10want to be passing in everything it
- 25:12needs and so it's more self
- 25:14enclosed that being said because the
- 25:16context of most scripts is very tightly
- 25:19coupled you know you're not trying to
- 25:21break stuff out to make it more reusable
- 25:23you're doing it just so it's easier to
- 25:25comprehend sourcing can be just fine and
- 25:27it'll save you from having to redeclare
- 25:29variables but the choice is yours you
- 25:32might notice that we haven't talked
- 25:33about functions yet and pretty much
- 25:36every language that you use you're going
- 25:37to be using functions a lot so it's kind
- 25:40of strange to not have touched on it yet
- 25:42but in truth I really don't use
- 25:44functions at all in bash save for a few
- 25:48situations and you'll see why in a
- 25:50second our function signature is
- 25:52function and then the name parenthesis
- 25:54and then we've got squiggly brackets
- 25:57absent you might notice is we don't have
- 25:59any arguments within the parenthesis
- 26:01that's one of the peculiarities of bash
- 26:03it's going to take in whatever is past
- 26:05into the function and then we can choose
- 26:07to do with it what we want now do note
- 26:10that when we're looking at the one and
- 26:11two variables here this is actually
- 26:14totally separate from The Wider script
- 26:16so you could have one and two at the
- 26:18global level but the one and two here is
- 26:21scoped to within this function call
- 26:23confusingly notice that we've got the
- 26:25local tool and local install URLs here
- 26:27that's because if we just declared the
- 26:29variables tool and install URL without
- 26:32specifying them as local they would
- 26:34actually be declaring them globally not
- 26:36locally to the function scope so kind of
- 26:38confusing that that behavior between
- 26:41those two isn't consistent but that's
- 26:43the way that it is so just got to deal
- 26:44with it but within the function you can
- 26:47do whatever you want you'll notice that
- 26:49the way that it works is very similar to
- 26:52a script so when we call out to it it's
- 26:54just like any other script or command so
- 26:56we can say insure dependen y passing in
- 26:58the arguments that we want no
- 27:00parentheses no nothing like that and the
- 27:01reason that I don't end up using this a
- 27:03lot say for instances like this or just
- 27:06have some small thing that I want to
- 27:07repeat over and over again is because
- 27:10the types of things you do in bass
- 27:11scripting tend to be relying on external
- 27:14tools and so any shared logic would be
- 27:17already pre-built into that then in
- 27:18other languages like let's say you're
- 27:20using python you really don't want to
- 27:22have a single function that does like 15
- 27:24things you're going to want to break
- 27:25those into separate functions even if
- 27:27you're only going to use them once but
- 27:30there isn't a huge amount of benefit to
- 27:31doing that within bash a quick little
- 27:34tip here is you might find yourself
- 27:36frequently I know that I have when I'm
- 27:38doing infrastructure stuff where I'm
- 27:39creating files and want to clean them up
- 27:42later there's this tool called M temp
- 27:45where if you do that from within a
- 27:47subshell it'll create a file inside of a
- 27:51temporary directory and then it'll
- 27:53reference that so you can assign some
- 27:55new variable to whatever the output is
- 27:57and then you can treat that just like
- 27:59any other file you have no idea where
- 28:01this file actually exists it's going to
- 28:02be likely in slm slash some random
- 28:05string and because it's in the temp
- 28:07directory it'll get cleaned up
- 28:09automatically at some point by your
- 28:10system but you can do this in
- 28:12combination with this trap command which
- 28:14will execute some given command in this
- 28:17case we're removing the temp file on a
- 28:19given signal and the signal we're
- 28:21looking for is exit so as soon as the
- 28:24script completes we get the exit signal
- 28:27in this command will be run the temp
- 28:28file will be cleaned up automatically so
- 28:30I find that very helpful and you can do
- 28:32the same thing for directories using
- 28:34make temp DD and then you can do
- 28:37whatever you want inside of that
- 28:38temporary directory and you can know
- 28:40that as soon as the script is completed
- 28:42all of that will be wiped automatically
- 28:44another quick thing to discuss is the
- 28:46naming Convention of the script
- 28:48themselves so do you do something like
- 28:50provision. sh or do you just call it
- 28:52provisioner and there's no strict rule
- 28:55around this but the way that I see it I
- 28:56like to do for anything that's like
- 28:58local to a project I'm going to use the
- 29:00dosh so it's very clear what this thing
- 29:02even is we know that it's a script but
- 29:05if I want it to be systemwide like a
- 29:07command that would run from anywhere in
- 29:09the system I'm just going to use
- 29:10provisioner in this case not provisioner
- 29:12Dosh because I don't care if provisioner
- 29:15is a script or if it's some binary or
- 29:17anything else I just know that I want
- 29:19this to run so that's how I look at it
- 29:22when you're trying to treat things like
- 29:23commands it's important to understand
- 29:25the path so if I was to call a command
- 29:28say we've got a command called blackout
- 29:30which will set my machine to night mode
- 29:32ordinarily you're going to call it with
- 29:34its file path so if it's in the current
- 29:36directory it'll look like this where
- 29:38it's do/ blackout you can also do
- 29:40absolute path but if I call it just
- 29:43blackout my shell is going to say hey I
- 29:46have no idea what that is and the reason
- 29:48for that is blackout doesn't happen to
- 29:50be in the path so what is the path well
- 29:53the path is an environment variable
- 29:55that's set in your shell that that lets
- 29:58it know exactly what directories to
- 30:00search in whenever it's looking for a
- 30:01command so it'll look something like
- 30:03this where we've got a series of
- 30:04directories they'll be separated by
- 30:07colons and whenever you run a command
- 30:10your shell will check across all of
- 30:12these directories and figure out which
- 30:15one actually contains that particular
- 30:18command and if that command doesn't
- 30:20happen to be found in any of those
- 30:21directories we'll get that command not
- 30:22found error so how do we Ramy that we've
- 30:26probably actually done this before many
- 30:28times you might not have been aware of
- 30:30what it's doing but there's this export
- 30:32path command that you'll run where you
- 30:33set the path to the current value the
- 30:35path and then you do colon and then you
- 30:37add on whatever new directory you want
- 30:39so I like to use a do scripts directory
- 30:42that lives in the home directory and I
- 30:43dump all my scripts in there you can do
- 30:45wherever you want but just remember that
- 30:47you need to export that in order to make
- 30:50them all accessible to your system but
- 30:52once you've run that now anywhere within
- 30:54that shell you can run blackout it
- 30:55doesn't matter if you're in the scripts
- 30:56directory or anywhere else it'll run
- 30:59just fine but that is only for the
- 31:01duration of that shell session so make
- 31:03sure to add your export path command to
- 31:06your Shell's configuration file so like
- 31:08your bash RC so with that we've covered
- 31:10everything that you need to know but I'm
- 31:12going to quickly walk you through the
- 31:14general process I go through whenever I
- 31:16create a new script so first and
- 31:17foremost you need to have some idea of
- 31:19what you're trying to do not really
- 31:21point in writing a script if you don't
- 31:22know what you're trying to solve but
- 31:23once you have that then you identify
- 31:26what tool you want to use
- 31:27the majority of what you're going to be
- 31:28doing in your actual script is just
- 31:31glooming together all these powerful
- 31:33tools that already purpose-built for
- 31:35some use case and you're just trying to
- 31:37glue them into some particular pattern
- 31:39that solves your problem so you figure
- 31:41out what tools you're going to be using
- 31:43and then you sketch it out in the
- 31:44terminal so you just do it manually run
- 31:47the commands and just play around until
- 31:49you figure out exactly what you want it
- 31:50to do from there you can then copy all
- 31:53those commands you can use history to
- 31:55pull all those commands out but grab
- 31:57them into a script from there you then
- 32:00parameterize it so pull out anything
- 32:02that will change between different runs
- 32:05and then create command line arguments
- 32:06and all that add some checks so if there
- 32:09are things that you need to make sure
- 32:11they're passed in or to make sure that
- 32:13files exist and so on you can add guard
- 32:15Clauses and all that and I say that at
- 32:17that point the majority of my scripts
- 32:19are done but sometimes things need to
- 32:21get more complex and so you'll have more
- 32:23advanced logic you might have loops you
- 32:25might have functions so you can add
- 32:27those in as necessary but I generally
- 32:29like to have all of this starting in a
- 32:31single file but then if things get too
- 32:34large then I break it into multiple
- 32:36files so quickly if we take a look at
- 32:38this process with an example the FFM P
- 32:41example I know that I wanted to create a
- 32:43script that will merge a video file and
- 32:45an audio file into a single output so I
- 32:48know that I'm going to use FFM Peg for
- 32:49this it's very good at that and so I can
- 32:53sketch it out I can run this ugly
- 32:54command to get it to work but now that I
- 32:57have this I'll just dump that directly
- 32:58into a script but we can see it's
- 33:00hardcoded with all these values like
- 33:03video. MP4 so I'll pull those out into
- 33:05variables and use commandline arguments
- 33:08so with that in place things are pretty
- 33:10good but let's add some checks so I want
- 33:14to make sure that I actually have three
- 33:15command line arguments because this
- 33:17would fail if I only passed in two so
- 33:20we'll print out a usage error and exit
- 33:23if not all that set but with that we're
- 33:25done with the fmeg example you could add
- 33:27additional checks like you could make
- 33:29sure that those files exist but for
- 33:31simple things like this I wouldn't
- 33:32bother another quick example so I work a
- 33:36lot with kubernetes so I like to be able
- 33:39to spin up local kubernetes clusters
- 33:41easily and I want to install some apps
- 33:43in them so the tools that I'm going to
- 33:46use are kind to provision the Clusters
- 33:49Cube control to interact with the
- 33:50cluster and Helm to install applications
- 33:53so if I sketch it out I'll run some
- 33:54commands like this or I'll run kind to
- 33:58create the cluster I'll run some Helm
- 34:00commands to add the repositories and do
- 34:03the upgrade and install and then at the
- 34:05end I'll use keepy control to port
- 34:07forward pretty simple example but I can
- 34:09dump that into a script and actually as
- 34:11it stands this could run just fine
- 34:13without any parameters or anything but
- 34:16there are things that we could
- 34:17parameterize like the cluster Name by
- 34:19doing this now I can support multiple
- 34:21clusters at once but I can still default
- 34:23to using just the playground name if I
- 34:26want to
- 34:27then I can add some checks right I need
- 34:29to make sure that these tools are
- 34:30actually available on my machine so kind
- 34:33Helm and Cube control this is the point
- 34:34where I'd figure out that hey actually
- 34:36this is very repetitive and I could pull
- 34:38this into a function like we saw this
- 34:41function previously to ensure
- 34:42dependencies and now I can reference
- 34:45those and I could as I grow and include
- 34:47more tools I can easily ensure that
- 34:49they're all available and obviously the
- 34:52script could keep growing it could do a
- 34:53lot more stuff so the general process
- 34:55again is just do the stuff manually and
- 34:57then iterate I think the worst thing you
- 34:59can do is try to write the entire script
- 35:02in one go and then only test it at the
- 35:04end I think just due to the nice nature
- 35:08of working with a shell language just
- 35:09like with python or JavaScript where we
- 35:11can use the reppel to play around and
- 35:13try things out because everything you
- 35:15write is the same as within the terminal
- 35:18there's no reason to not try things out
- 35:20manually and then dump them into the
- 35:21script once they're working all right so
- 35:24I've covered a whole lot there's more to
- 35:26the language and there's this great site
- 35:28called learn xiny minutes.com I'll link
- 35:30it down below but they've got a great
- 35:32guide on bash and pretty much any
- 35:34language that you should definitely
- 35:36check out that brings us to the end so I
- 35:39hope this has been helpful I hope that
- 35:40you go out there and write some bash
- 35:42scripts that save you a bunch of time
- 35:43and that you now have superpowers that
- 35:45will impress others as you can see bash
- 35:47is you know it's an awkward language in
- 35:50many ways but it's very powerful just
- 35:52due to the nature of calling out to all
- 35:54these other commands so thanks for
- 35:57watching and I will see you in the next
- 35:58one
About this transcript
This page contains the full transcript of Become a bash scripting pro - full course by Terminal Velocity, generated from the public captions YouTube serves with the video. The transcript has 7,336 words across 987 segments, with the original timestamps preserved so you can click any line to jump to that moment in the embedded player.
What you can do with it
Use the transcript to take notes, quote the speaker, build a study guide, generate a summary with ChatGPT or Claude via the YouTube Summary tool, or export it as a timed subtitle file with YouTube to SRT. You can also re-open it in the transcriber to translate the transcript into 100+ languages.
Free YouTube transcript tool
YouTube2Text is a free YouTube transcript generator — no signup, no daily limit. Paste any YouTube link and get the full transcript instantly, with timestamps, click-to-jump, translation to 100+ languages, AI prompts for ChatGPT, Claude, and Gemini, and exports to TXT, SRT, VTT, or Markdown.