Hey ๐โโ๏ธ Welcome, So You want to Learn Bash Scripting, I am creating a blog on Bash Scripting Which will be uploaded soon but before that you must know something about BASH and get familiar with some commands So let's Understand them.
What is Bash?
"Bash is a shell, a program that lets us interact with computer, giving us access to installed programs, hardware resources, and files stored on the system."
If you open a terminal window in Linux, chances are it's a bash shell. Bash is widespread on Linux systems. And it is not the only shell available for Linux. Having knowledge of Bash is an important foundation for any one using Linux.
The name Bash is short for Bourne Again Shell A reference to an earlier Unix shell, called the bourne shell. Bash takes a lot of what the Bourne shell offered, and adds in features from a variety of other shells, and includes other enhancements as well.
In many cases we'll use Bash to issue commands one-by-one at a command prompt. Bash allows us to combine these commands, along with control structures and other basic programming constructs, into scripts. Text files which contain a series of commands, and can be run like programs, And can also be shares with others.
Many Bash scripts are fairly short, and fairly straightforward. We'll often write a script, to combine a few commands we'd otherwise type one after the other at the command prompt And so Bash scripts help us to save time. And to avoid typos, or other manual errors that we might introduce.
Bash scripts also give us the ability to package up the series of commands that ask for or accept input from user. Allowing customizable commands to be used by people who might be uncomfortable, using the command line.
Bash is a flexible and versatile language, often giving us many ways to accomplish the same goal. Bash, isn't really the best choice for making a large complex programs. It's important to recognize when a task is best suited for different language.
Notes
Where to Run Bash ?
In order to run Bash we need to have bash and mostly it is pre-installed in most Linux systems, It is always good to check if it's available.
To do that
- Open terminal
- run
bash --version
The command shows us which version of bash is installed version 4.4 is currently the most wide spread and the minor version will be different on different systems
I am using bash version 4.2.*
There are different shell available in our system so to check the default shell we can use command echo $SHELL
this command gives us the available default shell in our system.
to move to the bash shell we can just use command bash
, this changes our shell to Bash
Pipes and redirection
Working with Bash we'll often need to control where output and input for commands are sent. There are two concept to deal with this piping and redirection.
Pipes
Piping :- Piping takes the result of one process and sends it to another process as though the output of first process were connected with the input of second process with pipe or tube.
Instead of displaying the output of the first process on the standard output, the output is sent along to the following process without being displayed on the screen.
For example :- we could use cat to take a look at the system's dictionary file which is really really long. And that's a bunch of stuff, it would be nice to take that output and display it page by page. We can do this by piping the output of ls into the less command.
Command :- cat /usr/share/dict/words | less
Note :- the word file can be present in different location on different OS. I am using Cent OS 7 machine.
Output :-
We can use arrow up or down to control and to quit we can use Ctrl + Z
Pipes are important in Bash Scripting because they let us piece together commands in order to build custom flows.
Pipes are very often used with tools like grep, awk, sed and cat which allow us to transform text from files or from the output of commands in useful ways.
Redirection
Redirection works with the standard input standard output and standard error. That is the input from the command line environment, the output to it, and the error that arise when something goes wrong.
A very basic example of redirection would be to take the output of a command like ls and send it to a file.
command :- ls > list.txt
We can also append the content in this list via redirection using >>
Command :- ls /bin >> list.txt
If we want to redirect the standard error i.e. message about problems that occur when a process runs we'll need to use the number 2 and greater than.
For example :- we will try to list a directory that didn't exist
We can see a message here. And it looks like the same as the text that I see at the standard output when a command sends me information there, but this is accessed in a different way.
So we can redirect the standard output with one, greater than sign and output.txt. 1 > output.txt
we can redirect the output with two greater than sign and error.txt. 2 > error.txt
the command only returns error so error is saved in error.txt file but nothing is saved in output.txt file.
When we work with files, we'll use these redirection to ensure that output goes where we need it to.
Input Redirection
We can also use input redirection, which uses the less than symbol to take information from a file to make it seem as though it was typed at the standard input the place where we provide input to the shell.
An example of that cat < list.txt
And we could just use cat to list this file on its own. Using input redirection here we can see how that works.
A variation of input redirection is called a hear document ant it lets us specify input freely up to a specified limits string, which can be useful for displaying long passage of text in a script or for providing input to an interactive command.
A Hear Document looks like this
cat << EOT
This is a
multiline
text string
used for
displaying
hear document
EOT
I used two less than symbols and a limit strig to say, "Take all of the multiline string and feed it into a single command"
Piping is used to send streams from one process to another. And redirection is used to sent streams to and from files.
Bash built-ins and other commands
When we're working with a shell, with bash in this case, most of what we do involves running commands. These commands are things like ls, rm, grep, arc and pretty much anything else you'd commonly use a shell to run.
These commands are separate from bash, they're separate programs that are installed on the system. But bash includes a few built-ins, or commands that are part of bash, built right into it, which we can use as well.
Sometimes these built-ins are unique to bash, and sometimes they have the same name as other commands on the system.
There's a list of built-ins in the bashman pages, but I'll just focus on a few here, that we'll be using going forward in the Blog.
One of these is echo, which outputs text. I'll type echo, and some text. Bash shows the text to me on the standard output.
One thing to know about echo, is that it ends the line with a new line character, which makes it useful for outputting text to the user and not having to worry about it appearing in a kind of unhelpful way.
As we see if we do the same thing with the printf built-in.
Printf and echo, both have their place when it comes to displaying text. Echo and printf are both shell built-ins, but there're also commands that are part of the GNU core utils.
Bash lets us specify whether to use a built-in or a command, which we might sometimes want to do, if the command version of a program offers features we need, that the built-in version doesn't.
we can run the command version of echo with command echo hello
, and I can explicitly run the built-in version by writing built-in echo text
.
Echo is a pretty standard program, so we don't have a difference now put here at all.
We can also tell whether something we run is a command or a built-in.
I'll do that with command -V df
here, and we can see that df is a program, located at bin/df. That's not a built-in.
command -V echo
it shows that the echo that the shell will run is the built-in.
Unless we specifically say to run the command version of echo, the shell will run the built-in version. And that's the case for any other built-in, with the same name as an existing program.
Built-ins take precedence over commands. That is to say, bash will run a built-in if it has one. Even if there's a command of the same name available on the system.
But specific built-ins can be disabled in a session, with enable -n and the name of the built-in
.
Doing this will allow the command version to run instead.
Now, when we run command -V echo
, we see that the shell will use the command version instead of the built-in.
enable -n by itself, shows the built-ins that are disabled.
Right now, it's just echo here on my system.
I can re-enable it with enable echo
.
Another important distinction to make here is that built-ins use a different documentation system than the regular man pages.
There's a built-in called help, that shows supporting information about built-ins.
For example, we can write, help echo
and find out what we can do with the echo built-in.
we will write help just by itself, and this will display the names of all the other built-ins.
Bash Built-ins are useful at the command line and also scripts, but it's important to know the difference between built-ins and commands.
Brackets and braces in Bash
Before we dig into Bash, I want to take a moment to talk about those curvy kind of semicircular characters that are so important to programmers: parentheses, braces, and brackets.
There's many names for each of these sets of characters, like circle brackets or round brackets, curly braces or flower brackets, and square brackets and closed brackets.
Often, the name varies by country or language.
In this Blog, I'll use parentheses, braces, and brackets to refer to them.
If you're accustomed to working with other programming languages like Python, JavaScript, C, Java, and so on, you're probably familiar with each of these symbols and you know what they're for in your language of choice.
Parentheses are often used for enclosing conditions and for function parameters.
Braces are used for function bodies and objects.
Brackets are used for lists or array notation.
In Bash, that's often a little different and in many cases, parentheses, braces, and brackets act as commands themselves.
So it can take a little getting used to if you're coming from other languages.
If Bash is the first language you're learning, you won't have that overhead to deal with. Just keep in mind that most other languages you might choose to explore later won't look like Bash when it comes to using these characters.
Bash expansion and Substitutions
When we're working with Bash, either at the command line or in a script, we'll often need to use values we don't know, things like a path to the user's home folder, a piece of user provided information, or the result of a calculation that's based on something we can't foresee.
Bash provides us a way to represent these values using expansions and substitutions. These are interpreted when they run and they replace themselves with a value or a set of values.
I want to introduce them now because they're very important to scripting. We'll take a brief tour of each expansion and substitution so you're more familiar with them when they pop up later in the Blog.
Tilde (~)
We'll start with tilde expansion which you might actually have already used without being aware of what's going on.
~ In bash, the tilde character represents the value of the user's home variable, and it's used in paths to represent the current user's home directory.
We can see that with echo ~
Tilde expansion is useful when we're scripting, because if we want to do something in a user's home directory, which is a pretty important place, we can do that without knowing their username.
Tilde just represents whatever the current users home directory is.
So here on my system, that's /home/vagrant, but on your system, the same tilde represents home and whatever your username is.
Brace expansion
Another useful type of expansion is called brace expansion.
This is written with braces around an expression and it lets us substitute in items from a list of values separated by commas, or ranges of numbers or letters in a given pattern, separated by two periods, or dots.
Brace expansion is often used when we need to keep part of a path the same but replace a little piece of it.
For example, if we wanted to create a file inside of each of three different directory trees, where only part of the path needs to change each time.
Or we could use it to provide a set of values to use in the same part of a string more generally.
The other form of brace expansion, which creates a sequence of numbers or letters is often used when working with sequential items.
To start with, I can write something like echo {1..500}.
That gives me the numbers 1 through 500
Or I could write echo and 500..1 to get the same numbers, but in a different order.
Adding a zero in front of the one here, I can tell Bash to pad the numbers to all be the same number of digits
which is helpful if you're using the numbers in a file name or something that needs to be sorted, or in an application where the number of digits needs to remain constant.
And it can generate letters, too. I'll write echo {a..z},
Or I could do the same with the capital letters sorted backwards.
With either kind of sequence, I can add an interval, too. To do that, I'll start like normal and then add another set of dots and a number to use as the interval.
This works with letters, too.
And I can combine brace expansions, too.
Let's generate a few files with sequential numbering, just for fun.
For each item in the first expansion set, Bash ran through the second expansion set. So I have 01a, 01b, 01c, and so on.
Brace expansion can also be used to work with set lists of things.
For example, I can write echo {cat,dog,fox}
Or I could write echo {cat,dog,fox }_{1..5}
We'll often find this used for directories or when working with files that have a predefined naming scheme.
Brace expansion can be used as a kind of shorthand when working with commands, too.
Parameter expansion ${..}
Parameter expansion, lets us recall stored values and transform them in various ways.
This is usually represented by a dollar sign and a set of braces. Though sometimes we'll see it without the braces.
The most straightforward use of parameter expansion is setting a value and then retrieving it as it will do when we make use of variables in scripting later on.
When we're using parameter expansion in this way, we set a parameter equal to a value and then use the dollar sign with the name of that parameter to retrieve the value later.
Parameter expansion also often features braces and those are used to make it clear what parameter is being used and to keep the shell from getting confused about nearby words or characters.
As an example here, I'll say that the parameter that I'll call greeting= "hello there!
To retrieve that value here at the command line, I'll write echo dollar sign and the name of that parameter.
And there's my value that I assigned to that parameter.
Parameter expansion can also be used to manipulate the stored value when it's used, transforming it in various ways, like just using part of the value or replacing certain parts of the value before it's used.
For example, I can write :-echo ${greeting:6}
and get the value of the parameter. Starting with the character at position six in the string
Or echo ${greeting:6:3}
to get the value starting at position six and then running for three characters from that point.
Here, the first character in the string is in position zero.
There are a variety of ways parameter expansion can be used and I'm not going to go through all of them here. They're listed in the bash man pages if you're curious.
One more parameter expansion feature that's useful though is pattern substitution. This lets us retrieve a value and transform it based on a pattern as we might do if we want to replace a particular word or character for some reason,
I write echo ${greeting/There/everybody}
I typed a slash and word which is what I'm telling bash to look for and another slash and the string that I want bash to replace that search term with. So I get back, hello, everybody and bash has replaced the pattern that I specified.
Using this notation we'll replace the first instance of a match
And using two slashes after the parameter we'll replace all of them.
Let's replace all of the 'e' with an underscore.
And to compare let's do the same thing with just one slash
and we can see the difference.
We will use braces for most parameter expansions, because if we left them off, the shell would just interpret the part after the parameter name, as characters and show them instead of using them to do what we intend.
Command Substitution $(...)
Command substitution, is a kind of special case expansion which allows us to use the output of a command within another command.
This is represented by a dollar sign and a set of parentheses in closing a command.
An alternate way of writing this, is to use two backticks, but that often gets confusing. So generally we write it with the parentheses.
Bash runs the specified command in a sub shell and returns the output of that command into the current command.
It's often used together with string manipulation tools to extract part of a commands output, such as a path, a file size, an IP address or so on, that needs to be handed back up to the parent command.
Let's take a look at using command substitution.
For example, we could use uname -r
to get the release version of the kernel.
And with command substitution we could use that in an echo statement.
We'll often use something like this in scripts to get the version of something the user has installed or some metrics about the system that might be relevant to how our script works.
We can use longer commands within the parentheses too, including command pipelines and you can nest command substitutions within one another in case you have a complex series of commands that depend on results of other commands.
Here I'm using python to print out a string and using tr to transform it to all caps. And then the result of that is being used in the echo statement.
That's getting a little sidetracked from Bash though. But you can see how it's useful to capture the output of a command and use it in another command.
Command substitution is often used with tools like grip, awk and cut in order to extract specific pieces of text from output
Arithmetic expansion $((..))
Bash can use arithmetic expansion to perform arithmetic, or math, and use the result in a command. This is represented by a dollar sign and two sets of parentheses with a mathematical expression inside.
Earlier versions of Bash also used a dollar sign with single brackets, but this is deprecated now. You may see it in older scripts, though.
Let's do a couple calculations here.
- First, I'll add two and two together.
- Then I'll subtract two from four.
- Then I'll multiply four by five.
And then I'll divide four by five.
This last one brings up an important point. Bash can only do math with integers. Four divided by five is 0.8, but because that's less than the integer one, we get zero as a result.
Expansions and substitutions are really important features of Bash and we'll rely on them heavily in scripts.
That's it for this blog. Stay updated for my next blog on BASH Scripting.
KEEP LEARNING ๐๐๐
Thank You.