In this lesson,
we're going to discuss the concepts
that lay the groundwork for writing your own scripts.
And we're going to do that by looking at scripting
and programming fundamentals.
Now, before we start to create your own scripts
with bash though,
you need to start getting familiar
with some of the basic concepts
that are shared by many scripting
and programming languages used today.
Bash is not only the default shell
of the Linux operating system,
but it's also a powerful scripting language.
Now bash scripting is a skill
that any system administrator really needs to learn
because it's something that's going to help you
leverage your time and really automate
a lot of the things you do on a daily basis.
By using bash scripting,
you can leverage Linux as existing tools
to get things done much quicker.
Essentially, any program tool, utility or system function
that you can call it the command line,
you can also invoke from within a bash script.
Similarly, bash scripts
also support modern programming elements
like loops and conditional statements
to enhance the logic of the task that are being automated.
Just as the commands inside the command line interface
have a certain syntax,
your scripting languages also have specific syntaxes
that have to be used.
When I talk about syntax,
I'm simply referring to the rules
that define how you're going to write your code.
Each scripting and programming language has its own syntax,
but many share a few commonalities.
Because the Bash is really the default
inside the Linux operating system,
you're going to see that the syntax of the bash script
is very similar to what you learned
when you inputted things line by line
within the command line environment.
Now your bash script may contain shell specific instructions
that are not compatible with other Linux shells though.
Remember, in Linux,
you can choose what shell environment you want to use.
We're using bash in this course,
but you could really use anything you want
such as the C shell, Z shell or others.
To specify that your script
is being written for the bash shell,
you need to add the line #bang/bin/bash
at the beginning of each script.
Anytime you hear the word bang,
that means the exclamation mark.
Now this line will instruct the operating system
to use the bash shell interpreter
when they execute this script
on an incompatible Linux shell,
and that way your script can still operate on that system.
Now, another thing we're going to do inside of our scripts
is assign variables.
And we assign variables to symbolically associate
a specific piece of information with a given name,
and then we can refer to that name
when we want to get that piece of information.
Lots of different programming languages like C
are going to require you to define the type of variable
before you assign a value to it.
This includes things like integers, floats,
strings and other characteristics.
Essentially, these types define exactly
what kind of information that variable can hold.
However, in bash, you don't have to declare variable types.
All bash variables are treated as strings by default,
and therefore you can put any kind of data you want
inside of that variable.
Now, one unique thing about assigning values
in bash to a variable
is that you're going to make sure there are no spaces
before or after the equal sign.
For example, if I was assigning Jason Dion
to the variable myname,
I would type in myname equals 'Jason Dion'
and that's it, no spaces except between Jason and Dion.
And it's okay to have the space there
because I have the quotes around that string.
Now, after you assign a value to a variable,
you can reference that variable later on in your code,
so you don't have to hard code these values
into your script's logic.
The act of referencing or retrieving the valuable variable
is known as substitution or parameter expansion.
Now, when you're referencing variables in bash,
you're going to do this by adding a dollar sign
to the beginning of the variable name.
For example, if I wanted to display myname to the screen,
I would do that by typing echo $myname,
and this will print out Jason Dion
into your console or command line environment.
So note that when you're assigning the variable,
you don't use the dollar sign,
but when you're pulling information from that variable,
you use the dollar sign.
Now, in addition to storing data
and retrieving data from a variable,
there's other operations you can do with these variables
to create tasks and outcomes that you're looking for.
For example, you might need
to be able to evaluate the condition of a variable
and what's stored inside of it.
This is known as a comparison,
and we do this using operators.
Now operators are the object that can evaluate expressions
in a variety of different ways.
When we look at operands,
these are the values that are being operated on.
So there's lots of different kinds of operators
that we can apply inside of bash.
We have arithmetic operators, comparison operators,
logical operators, and string operators.
Let's take a quick look at each of these.
First, we have arithmetic operators.
These include things like adding, subtracting, multiplying,
and dividing and other more advanced mathematical functions.
For example, if I had variable one and variable two,
and I wanted to add them together,
I can do that by using a double parenthesis around them.
And so I would say dollar sign, parenthesis, parenthesis
var one plus var two, parenthesis parenthesis.
And this will take the values of variable one
and variable two and add them together
and display that to the screen
if it was inside of an echo command.
Now comparison operators are going to be used
to check if things are equal,
if something is less than or greater than the other,
or other things like that.
For example, if I'm going to do a comparison
to see if variable one is greater than
or equal to variable two,
I would do that by typing bracket, dollar sign,
var one -ge dollar sign var two, end bracket.
Now notice here I'm using brackets instead of parentheses,
that's because I'm using a comparison operator.
And the return value from this comparison
is either a one if it's true or a zero, if it's false.
The next one we have is a logical operator.
And logical operators are used
to connect multiple values together
so they can be evaluated.
Normally these are things like, and, or, and not.
For example, if I wanted to test two different conditions
and then see if they are both true,
I would use an and operator,
which is symbolized by the ampersand ampersand sign.
So I might do something like bracket dollar sign var one
ge dollar sign var two, bracket,
ampersand, ampersand bracket, dollar sign var three, -le
dollar sign var four, bracket.
This says, tell me is variable one
greater than or equal two variable two
and is variable three less than or equal two variable four.
This is how you connect things together
by using ands, ors and nots.
When you want to use a not,
it's going to be a bang equal sign.
If you want to use an or, it's going to be two pipes,
which is the up and down straight line characters,
right above your enter key.
Next, we have string operators.
Now string operators are going to be used in operations
that manipulate strings in various ways,
including concatenating strings,
returning a specific character in a string,
which is known as slicing or verifying
if special characters exist inside of a string.
For example, if I wanted to concatenate two variables
and put them together, I can take dollar sign var one,
dollar sign var two, with no spaces in between them,
and this will put them both together as a single word
or single string when being displayed
to the command line environment.
Now, the next thing we want to talk about is a string literal.
A string literal is any fixed value
that represents a string of text within your source code.
String literals are enclosed either single
or double quotation marks,
and as long as you're using them consistently,
you can use either single or double quotation marks.
It really doesn't matter. It's up to you.
However, there are some cases where double quotes
won't preserve the literal value
of all the characters within those quotes.
For example, let's go back to the example
of having myname as a variable
that contains Jason, space, Dion.
Now let's say I wanted to substitute this variable
into a larger literal strength.
I can do that by typing
echo " my name is dollar sign, myname"
and this is going to print
My name is Jason Dion over to your screen.
Now, on the other hand, if I use single quotes
and typed echo 'My name is dollar sign, myname'
this is going to print out to the screen,
My name is dollar sign myname
because it's not actually parsing that variable
because I use single quotes instead of double quotes
in this particular example.
In general, it's a great idea
to always put quotes around your strings
when you're assigning them to a variable.
This is especially important
if you have spaces in the variable,
such as Jason space Dion, that I was assigning
into the myname variable.
If you don't do that,
it's only going to sign the first word
instead of the entire phrase.
So in that case, I'd only have Jason stored
instead of Jason space Dion.
Now, if it's a single word, you don't need quotes.
But again, it's just a good practice to always use quotes
around what you're setting your variable names to.
Now in any language, including bash,
there are certain characters that have special meanings.
And these characters are basically what we call
reserved characters.
Let's talk about a few of them here.
First, we have an escape character.
Now an escape character is used
to remove that special meaning
so that any character can be used literally
rather than as an interpreted thing by the system.
For example, you saw the fact that we use hashtags
as a way to start a comment on a line
or to describe what this script is
by doing the hashtag bang at the beginning of the script.
Well, what if I wanted to tell you
that I wanted to be number one
and put that hashtag in front of the one
when I display it to the screen.
If I did that normally, it's just going to go ahead
and process everything at the end of that line as a comment.
So I need to first escape this special meaning
from that hashtag character.
To do this, I can use an escape character
such as a single back slash.
This single back slash will be put
right in front of that character.
And so if I said, I am number one,
I'm going to write that as I am single back slash,
pound sign, one, and that way it'll process
as the pound sign and not as a comment character.
This is the way you can escape something
and take away that special meaning.
Another way to do this is by using single quotation marks.
So if I put single quotation marks around that string of
I am number one, it's still going to process
as I am number one.
Alternatively, if you wanted to use double quotes
or no quotes,
then you're going to have to use that escape character
of using that single back slash.
The next thing we're going to talk about is an array.
Now, an array enables you to store multiple values
in a single variable.
This can make your code much easier to read and maintain
because you don't have
to have a bunch of different variables.
You can have one that contains everything you need.
For example, you might want to perform
a single mathematical operation
on dozens of different values.
And instead of creating a variable for each value,
you can create an array to simplify your code
and store all those values in different parts of the array.
Another benefit of arrays
is that you can easily update their values
throughout the code because it's a single thing
instead of having multiple different variables.
Now, when you do compound assignments inside bash arrays,
you're going to use parentheses
with each value being separated by a space.
For example, let's say I created an array called my array
and I want to store three words inside of it.
Jason, Dion, and training.
To do this, I'm going to type in my array equals parenthesis,
double quote, Jason, double quote,
double quote, Dion, double quote,
double quote, training, double quote, and parentheses.
Now, in addition to assigning the array all at once
like I did here,
I can also individually assign things
into the specific values based on their indexes
and I place that in a bracket.
So for example, if I wanted to get the word, Jason,
I would do my array bracket zero bracket equals,
double quote, Jason double quote,
and that assigns the word Jason into space zero,
which is the first space in this particular array.
I can do the same thing with Dion and training.
by using my array one and my array two,
and putting those values into there.
You can always reference an array
by wrapping it in curly braces
when you want to get information back out of it.
So if I wanted to pull out the name, Jason,
I can do echo dollar sign, curly brace, my array,
bracket, zero bracket, curly brace,
and this would return the value of Jason from position zero,
which is the first position inside of that array.
Now, another thing we need to talk about quickly
is functions.
Now functions are a block of code that you can reuse
to perform a specific task.
This is really useful
when you're trying to write efficient code.
So you don't have to copy and paste things over
and over again.
And so we'll call the function
and somehow to write out the same thing over and over again.
Just like a variable, you can define a function
using a unique name or identifier,
and then you can reference that identifier
to be able to do all the things inside that function
based on its code.
So in bash, there's really two ways to write functions
and both involve placing the desired code
between a set of curly braces.
Now, the first method is going to be something like this.
Function, my function name, curly brace code, curly brace,
and all your code goes inside those curly braces.
Now, if you're familiar
with using object oriented programming
and you come from a background like C or Java,
you might be more comfortable using the second method.
And the second method is my function name,
parenthesis parenthesis, and then curly bracket,
all the code you want, end curly bracket.
Notice both will do the same thing,
it's just a different way of writing it,
depending on which method you prefer.
Now in bash,
when you want to pass arguments into your function,
you're going to do it the same way you would
with a script at the command line.
So if I want to send an argument in such as Jason
into the my function name,
I would simply enter my function name, space, Jason.
And that means Jason is the first argument
that's being passed into my function name.
And then the code will execute upon it.
Now in the world of programming,
we often want to comment our code
so other people can know what we're doing.
And as I said before, the hashtag symbol
is going to indicate that everything after that,
on that particular line is part of the comment
and will not be executed by the system.
You should refrain from commenting on a line of code
whose purpose is obvious,
because too many comments can corrupt your source code.
But in general, it is a good idea
to at least comment what the function is that you're doing
or what the logic of the next several lines is,
so somebody else coming behind you
can understand what you're doing.
Another thing we need to talk about is metacharacters.
Now metacharacters are special characters
that the shell will by default interpret in a certain way.
These characters have to be escaped or enclosed in quotes
if you want them to be interpreted literally.
Similar to the hashtag I just mentioned.
Now let's talk about these different metacharacters,
because it's important to know what characters
are reserved in Linux.
The first one is the greater than symbol,
which is used in output redirection.
We also have the greater than greater than symbol,
which is used in output redirection too,
but in a different manner.
We have the less than symbol,
which is used in input redirection.
We have the less than less than symbol,
which is used for input redirection as well,
but a different context.
We have the up and down bar,
which is used to pipe content from one command into another.
We also have the double quote,
which is used for defining weak literal strings.
We have the single quote,
which is used for defining strong literal strings.
We have the backwards tick mark,
which is used for breaking out of a literal string
to run the command that's inside of it.
We have a single backwards slash
which is used to escape all these other characters.
We have the equal sign,
which is used for variable assignment.
We have the dollar sign,
which is used for variable substitution
and pulling information back out of a variable.
We also have the hashtag, which is used for commenting.
We have the double pipe,
which is used for logical or operations.
The double ampersand,
which is used for logical and operations.
The star, which is used for wildcard matching.
The question mark,
which is used for wildcard matching
being applied on a single character
instead of multiple characters.
We have the brackets which are used for wildcard matching
any applied character between those brackets.
We have the curly braces,
which is used in perimeter substitution and arrays.
We have parentheses, which is used for grouping commands.
We have a single ampersand by itself,
which is used for running a process in the background.
We have the semicolon,
which is used for separating multiple commands
on the same line.
And we have the bang or exclamation character,
which is used in referencing command history.
All of these are considered reserve characters
and metacharacters,
and you should be aware of what they are
and their functions.
Now on Unix and Linux systems,
programs can also pass the value to their parent process
when they terminate.
This is known as an exit code or exit status.
In the Linux world, a status code of zero
indicates that the process executed successfully,
whereas an exit code of one or any number higher than that
means that the process encounters some kind of an error
when it executed.
Now, when you're creating your own scripts,
you want to make sure you take into account exit codes.
Because when you write a script,
it's often going to be used by other people
in their scripts too,
and you can call from one script to another.
And by being able to have that exit code come back,
it can tell them the status of your script,
that it was successful or not.
Again, if you use exit code one,
this can cause the script to terminate
with a failure status.
Whereas zero would say everything was satisfactory,
keep on going.
These exit codes are going to exist within your scripts,
even if you don't define them,
but by defining them and using proper exit codes,
you can have multiple different errors
that you can test for,
and then you can give that information back
to the script that's calling you.
For example, maybe zero is going to be successful.
One is going to be a failure.
Two is going to be the fact that nobody gave you an argument
to process in the first place.
Things like that can be used as a way to give information
from one script to another or one program to another.
Now, another thing you want to take advantage of
is the ability to do redirection
and piping within the command line environment.
You can do this by redirecting exit codes,
either to the standard out, standard error
or standard in, depending on what you want to do.
And you can also redirect data to and from different files
by using your redirections.
Another thing to be aware of
is how the bash shell actually interprets commands.
And the way it does this is to split things up into tokens,
also known as words.
Shell expansion is the process
by which the shell identifies these special tokens
and then substitutes in values for them.
Variable substitution is a type of shell expansion
by which the shell going to identify
that dollar sign special character,
and then expand the value
into its actual value that's being stored.
In other words,
when I do something like echo dollar sign variable,
the echo command doesn't see the variable,
instead it sees what the variable represents
and what was stored inside of it
because bash is going to expand it,
before passing it over to the echo command.
Now bash is going to perform its expressions
in a defined order.
Very similar to the order of mathematical operations
you learned back in high school.
The order of expansion
is always going to start out with brace expansion first,
then tilde expansion,
then parameter and variable expansion,
then arithmetic expansion and then command substitution,
and then word splitting and then file name expansion.
The shell will always perform things in that order,
as it performs its expansions and substitutions.
Now, when do you want to include a command's output
within an existing string of text,
command substitution can actually be used.
This is a method where shell expansion
allows the output of a command
to replace the command itself.
For example, if I enter the command, echo double quote,
the current directory is backwards tick mark,
pwd backwards tick mark, quote,
this is going to actually replace the pwd
and replace it with what the present working directory is.
And this would output something like,
the current directory is /root,
if that was your present working directory.
Now another way to do this
is to use the format of dollar sign parenthesis,
command, parenthesis.
This will perform command substitution as well.
For example, I could type this out by doing echo, quote,
the current directory is dollar sign parenthesis,
pwd, parenthesis, quote.
And this would then do the exact same thing.
Now, another thing we need to talk about is globbing.
Now globbing is a bass shell feature
that's used for matching
or expanding specific types of patterns.
Globbing is mainly used to match file names
and searching for content within a given file.
Globbing is going to rely on wild card characters
to create different patterns,
and that way you can find the information
you're looking for.
Now, there are three most commonly used wild card characters
when you're creating a globbing pattern.
These are the star, the question mark
and the square brackets.
First, we have the star also known as an asterisk.
This is going to be used to match any number of characters.
For example, if I type in cp star.txt
tilde/destination,
this is going to copy all the files with a .txt extension
because that wild card is appearing before the period.
And that means anything .txt is going to match my criteria.
Now it's important to realize that when you're using a star
or an asterisk, it's not replacing a single character,
it's replacing zero characters,
one characters or infinite number of characters.
So if I had a file called .txt
or a file called one.txt or a file called Jason.txt,
all three of those will match the wildcard
of star.txt because they all end with .txt,
even if there's nothing before the dot.
The second one we have is a question mark.
Now the question mark is used to match a single character.
For example, if I was looking for any file
that had a single letter .txt,
and I wanted to copy those to my destination directory,
I could do that by typing in cp ?.txt
tilde/destination.
And this is going to copy files like a.txt, b.txt, c.txt,
but it won't do Jason.txt
because that's too many characters.
Note here that if I do have that question mark,
it can also represent a zero character.
So .txt would still match just like a.txt and b.txt,
but Jason will not because that's too many characters.
The third type we have is notice square brackets.
And any characters you put between the square brackets
can be used to match any of the characters
that are listed inside of there.
For example, let's say I did something like cp bracket,
ABC bracket .txt tilde/destination.
What will this do?
Well, it's going to copy all the files
that are named a.txt, b.txt or c.txt.
Notice inside those square brackets,
we're only going to pick one letter
out of the combinations there and be able to use those.
So if I wanted to put all the letters like A through Z,
I could do that by doing a dash Z
inside those square brackets.
And now I'm going to find every single file
that starts with one of the letters .txt,
which would be very similar to using the question mark.
But if I wanted to be able to have just a, b and c,
putting those inside my brackets will give me those options.
Now, the next thing we're going to talk about
is a positional parameter.
Now positional parameter
is a variable within your shell script
that's assigned to an argument when the script is invoked.
For example, let's say I call the script dion.sh
by typing dion.sh arg one, arg two, arg three.
Now the arg one argument corresponds to the first position
which we refer to as dollar sign one.
Arg two corresponds to the second position, dollar sign two,
and arg three corresponds to the third position,
dollar sign three, and so on.
Notice there's a space between each of these arguments
and that space is used
to separate those positional parameters.
So let's go ahead and look at dion.sh
this little script I have.
I have four lines.
The first line defines that this is a bash script
by doing hashtag exclamation slash bin slash bash.
And then the next three are all looking the same,
but the only difference is which argument we're calling.
Echo dollar sign one is the first argument,
echo dollar sign two is the second argument
and echo dollar sign three is the third argument.
Now, if I call this script by entering dion.sh,
space, Jason space, dion space, training,
what am I going to get back?
Well, I'm going to get three sentences back that say,
Jason is the first argument,
Dion is the second argument
and training is the third argument.
Now this is a really simple script,
and all it's doing is echoing out information
that we gave it from the command prompt.
Now, what happens if I forget to give any arguments?
Well, let's say I just run it as dion.sh,
what's going to happen?
Well, it's going to return the three sentences,
but the arguments are being filled in with a blank space
because we didn't give it any arguments.
So we're going to get blank as the first argument,
blank is the second argument
and blank is the third argument displayed on our screen.
Now, if you want to hard code the arguments into the script,
you can do that by using something known as set.
So we're going to modify our script by adding a new line
that says set space dash dash space, CompTIA space,
Dion space, training.
Now because I've hardcoded those arguments into the script,
I don't have to enter them at the command line.
So I simply enter dion.sh and hit enter,
and these three sentences are going to be returned
to the screen with those arguments filled in.
So now I get CompTIA is the first argument,
Dion is the second argument,
training is the third argument and so on.
Now note because I hardcoded those into the script
using the set command,
I can no longer pass those arguments from the command line
and overwrite them.
So if I entered in the command I used before
of dion.sh space, Jason space, Dion space, training,
I'm still going to get the same three sentences out
that I got before with those hard coded arguments,
because it's going to say CompTIA is the first argument,
not Jason is the first argument
because CompTIA is hard coded inside of the script,
and so we're going to ignore the arguments
passed from the command line.
Now, the next command we're going to talk about is exec.
Now the exec command does not create a new process
when you run it.
Instead, it only replaces the bash shell
with the command being executed.
Now, this is useful if you want to prevent the user
from returning to a parent process inside your script,
when there's an error that's encountered.
For example, you might want to terminate a privileged shell
if a command fails.
And if no command is supplied,
the redirections are going to be used
to modify the current shell environment.
This can be very useful to allow us
to change the file descriptors of a shell
based on our desires.
The process is going to continue even after the exec command,
unlike the previous case,
but now standard input, output and error
are modified according to the redirections that we have.
Another command we have to know about is source.
The source command is used to execute another command
within the current shell process.
In this sense, it really performs the opposite function
of the exec command.
This is really useful when you'd like
to stay within your current shell
when you're executing a script.
For example, let's say you wanted to change a directory
inside of your script.
Well, you'd probably want to source that first
and by sourcing it, it means that after the script executes,
your location will be whatever directory you change to
inside of the script,
because the script was operating
just as if you were typing in those commands.
Now for the most part,
Linux file extensions are really optional.
You don't need them on everything,
but you'll notice I use .sh
when I gave an extension to my bash script.
Why is that?
Well, it's because Linux checks the files metadata
to determine what type of file it is.
But those .shs and .txts, that helps us as humans
know what type of a file we're looking at.
So you don't really need to name your scripts
with an extension, but by default,
we do add .sh as an extension for shells scripts
to ensure that everybody understands that that is a script
and it has special meaning to us.
It really is for the people and not for the computer,
which is something to be aware of.
Remember your ability to use any file,
including a script is really only going to be constrained
by the permissions assigned to that script
and your user account.
So even though you created a script,
you're not going to automatically have permissions to run that
unless you do a change mod command
and you give it execute abilities.
So make sure you set two permissions
every time you write a script.
First, you need to ensure that your user
has the permissions to execute the script itself.
And second, you want to make sure that you have right
and execute bits set on the directory
that contains that script.
If that directory doesn't have the execute bits set,
it's not going to allow you to be able to run that script,
even if the script is set to execute.
Remember, you can always control who can access the files,
search their directories and run scripts
using Linux's change mod command
by being able to apply or remove, read, write,
and execute bits onto those directories and files.