Introduction to Bash Scripting
Introduction to Bash Scripting
Table of Contents
Sponsors ................................................................................................................ 10
License .................................................................................................................. 15
If statement ........................................................................................................... 42
Conclusion ............................................................................................................. 48
Example ................................................................................................................ 63
Conclusion ............................................................................................................. 67
Conclusion ............................................................................................................. 78
Conclusion ............................................................................................................. 88
Prerequisites .......................................................................................................... 90
Conclusion ............................................................................................................. 94
Installing jq ............................................................................................................ 97
BASH Script parser to Summarize Your NGINX and Apache Access Logs ..... 113
This is an open-source introduction to Bash scripting guide that will help you learn the
basics of Bash scripting and start writing awesome Bash scripts that will help you
automate your daily SysOps, DevOps, and Dev tasks. No matter if you are a
DevOps/SysOps engineer, developer, or just a Linux enthusiast, you can use Bash
scripts to combine different Linux commands and automate tedious and repetitive daily
tasks so that you can focus on more productive and fun things.
The first 13 chapters would be purely focused on getting some solid Bash scripting
foundations, then the rest of the chapters would give you some real-life examples and
scripts.
8
TELEGRAM: CODINIT( click here)
About the author
My name is Bobby Iliev, and I have been working as a Linux DevOps Engineer since
2014. I am an avid Linux lover and supporter of the open-source movement philosophy.
I am always doing that which I cannot do in order that I may learn how to do it, and I
believe in sharing knowledge.
I think it's essential always to keep professional and surround yourself with good
people, work hard, and be nice to everyone. You have to perform at a consistently
higher level than others. That's the mark of a true professional.
9
TELEGRAM: CODINIT( click here)
Sponsors
Materialize
The Streaming Database for Real-time Analytics.
DigitalOcean
DigitalOcean is a cloud services platform delivering the simplicity developers love and
businesses trust to run production applications at scale.
It provides highly available, secure, and scalable compute, storage, and networking
solutions that help developers build great software faster.
Founded in 2012 with offices in New York and Cambridge, MA, DigitalOcean offers
transparent and affordable pricing, an elegant user interface, and one of the largest
libraries of open source resources available.
If you are new to DigitalOcean, you can get a free $100 credit and spin up your own
servers via this referral link here:
DevDojo
The DevDojo is a resource to learn all things web development and web design. Learn
on your lunch break or wake up and enjoy a cup of coffee with us to learn something
new.
Join this developer community, and we can all learn together, build together, and grow
together.
Join DevDojo
10
TELEGRAM: CODINIT( click here)
For more information, please visit https://www.devdojo.com or follow @thedevdojo on
Twitter.
11
TELEGRAM: CODINIT( click here)
Ebook PDF Generation Tool
12
TELEGRAM: CODINIT( click here)
Ebook ePub Generation Tool
13
TELEGRAM: CODINIT( click here)
Book Cover
If you ever need to create a graphic, poster, invitation, logo, presentation – or anything
that looks good — give Canva a go.
14
TELEGRAM: CODINIT( click here)
License
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
15
TELEGRAM: CODINIT( click here)
Welcome to this Bash basics training guide! In this bash crash course, you will learn
the Bash basics so you could start writing your own Bash scripts and automate your
daily tasks.
Bash is a Unix shell and command language. It is widely available on various operating
systems, and it is also the default command interpreter on most Linux systems.
Bash stands for Bourne-Again SHell. As with other shells, you can use Bash
interactively directly in your terminal, and also, you can use Bash like any other
programming language to write scripts. This book will help you learn the basics of
Bash scripting including Bash Variables, User Input, Comments, Arguments, Arrays,
Conditional Expressions, Conditionals, Loops, Functions, Debugging, and testing.
Bash scripts are great for automating repetitive workloads and can help you save time
considerably. For example, imagine working with a group of five developers on a
project that requires a tedious environment setup. In order for the program to work
correctly, each developer has to manually set up the environment. That's the same and
very long task (setting up the environment) repeated five times at least. This is where
you and Bash scripts come to the rescue! So instead, you create a simple text file
containing all the necessary instructions and share it with your teammates. And now,
all they have to do is execute the Bash script and everything will be created for them.
In order to write Bash scripts, you just need a UNIX terminal and a text editor like
Sublime Text, VS Code, or a terminal-based editor like vim or nano.
16
TELEGRAM: CODINIT( click here)
Bash Structure
Let's start by creating a new file with a .sh extension. As an example, we could create
a file called devdojo.sh.
touch devdojo.sh
nano devdojo.sh
In order to execute/run a bash script file with the bash shell interpreter, the first line of
a script file must indicate the absolute path to the bash executable:
#!/bin/bash
All that the shebang does is to instruct the operating system to run the script with the
/bin/bash executable.
17
TELEGRAM: CODINIT( click here)
Once we have our devdojo.sh file created and we've specified the bash shebang on
the very first line, we are ready to create our first Hello World bash script.
To do that, open the devdojo.sh file again and add the following after the
#!/bin/bash line:
#!/bin/bash
chmod +x devdojo.sh
./devdojo.sh
bash devdojo.sh
As bash can be used interactively, you could run the following command directly in
your terminal and you would get the same result:
18
TELEGRAM: CODINIT( click here)
Putting a script together is useful once you have to combine multiple commands
together.
19
TELEGRAM: CODINIT( click here)
Bash Variables
As in any other programming language, you can use variables in Bash Scripting as
well. However, there are no data types, and a variable in Bash can contain numbers as
well as characters.
name="DevDojo"
Notice: as an important note, you can not have spaces before and after the =
sign.
After that, to access the variable, you have to use the $ and reference it as shown
below:
echo $name
Wrapping the variable name between curly brackets is not required, but is considered
a good practice, and I would advise you to use them whenever you can:
echo ${name}
The above code would output: DevDojo as this is the value of our name variable.
Next, let's update our devdojo.sh script and include a variable in it.
Again, you can open the file devdojo.sh with your favorite text editor, I'm using
nano here to open the file:
20
TELEGRAM: CODINIT( click here)
nano devdojo.sh
Adding our name variable here in the file, with a welcome message. Our file now looks
like this:
#!/bin/bash
name="DevDojo"
./devdojo.sh
Hi there DevDojo
You can also add multiple variables in the file as shown below:
#!/bin/bash
name="DevDojo"
greeting="Hello"
21
TELEGRAM: CODINIT( click here)
Save the file and run it again:
./devdojo.sh
Hello DevDojo
Note that you don't necessarily need to add semicolon ; at the end of each line. It
works both ways, a bit like other programming language such as JavaScript!
You can also add variables in the Command Line outside the Bash script and they can
be read as parameters:
This script takes in two parameters Bobbyand buddy! seperated by space. In the
devdojo.sh file we have the following:
#!/bin/bash
$1 is the first input (Bobby) in the Command Line. Similarly, there could be more
inputs and they are all referenced to by the $ sign and their respective order of input.
This means that buddy! is referenced to using $2. Another useful method for reading
variables is the $@ which reads all inputs.
22
TELEGRAM: CODINIT( click here)
#!/bin/bash
# $1 : first parameter
# $2 : second parameter
# $@ : all
23
TELEGRAM: CODINIT( click here)
With the previous script, we defined a variable, and we output the value of the variable
on the screen with the echo $name.
Now let's go ahead and ask the user for input instead. To do that again, open the file
with your favorite text editor and update the script as follows:
#!/bin/bash
The above will prompt the user for input and then store that input as a string/text in a
variable.
We can then use the variable and print a message back to them.
./devdojo.sh
Once you've typed your name, just hit enter, and you will get the following
output:
24
TELEGRAM: CODINIT( click here)
Hi there Bobby
Welcome to DevDojo!
To reduce the code, we could change the first echo statement with the read -p, the
read command used with -p flag will print a message before prompting the user for
their input:
#!/bin/bash
25
TELEGRAM: CODINIT( click here)
Bash Comments
As with any other programming language, you can add comments to your script.
Comments are used to leave yourself notes through your code.
To do that in Bash, you need to add the # symbol at the beginning of the line.
Comments will never be rendered on the screen.
#!/bin/bash
Comments are a great way to describe some of the more complex functionality directly
in your scripts so that other people could find their way around your code with ease.
26
TELEGRAM: CODINIT( click here)
Bash Arguments
You can pass arguments to your shell script when you execute it. To pass an argument,
you just need to write it right after the name of your script. For example:
./devdojo.com your_argument
In the script, we can then use $1 in order to reference the first argument that we
specified.
#!/bin/bash
chmod +x arguments.sh
27
TELEGRAM: CODINIT( click here)
#!/bin/bash
Another thing that you need to keep in mind is that $0 is used to reference the script
itself.
This is an excellent way to create self destruct the file if you need to or just get the
name of the script.
For example, let's create a script that prints out the name of the file and deletes the file
after that:
#!/bin/bash
rm -f $0
You need to be careful with the self deletion and ensure that you have your script
backed up before you self-delete it.
28
TELEGRAM: CODINIT( click here)
Bash Arrays
If you have ever done any programming, you are probably already familiar with arrays.
But just in case you are not a developer, the main thing that you need to know is that
unlike variables, arrays can hold several values under one name.
You can initialize an array by assigning values devided by space and enclosed in ().
Example:
To access the elements in the array, you need to reference them by their numeric
index.
echo ${my_array[1]}
echo ${my_array[-1]}
As with command line arguments using @ will return all arguments in the array,
as follows: value 1 value 2 value 3 value 4
echo ${my_array[@]}
29
TELEGRAM: CODINIT( click here)
Prepending the array with a hash sign (#) would output the total number of
elements in the array, in our case it is 4:
echo ${#my_array[@]}
Make sure to test this and practice it at your end with different values.
30
TELEGRAM: CODINIT( click here)
Substring in Bash :: Slicing
#!/bin/bash
letters=( "A""B""C""D""E" )
echo ${letters[@]}
Output:
$ ABCDE
Example 1
#!/bin/bash
letters=( "A""B""C""D""E" )
b=${letters:0:2}
echo "${b}"
This command will print array from starting index 0 to 2 where 2 is exclusive.
$ AB
Example 2
31
TELEGRAM: CODINIT( click here)
#!/bin/bash
letters=( "A""B""C""D""E" )
b=${letters::5}
echo "${b}"
This command will print from base index 0 to 5, where 5 is exclusive and starting index
is default set to 0 .
$ ABCDE
Example 3
#!/bin/bash
letters=( "A""B""C""D""E" )
b=${letters:3}
echo "${b}"
This command will print from starting index 3 to end of array inclusive .
$ DE
32
TELEGRAM: CODINIT( click here)
In Bash, conditional expressions are used by the [[ compound command and the
[built-in commands to test file attributes and perform string and arithmetic
comparisons.
Here is a list of the most popular Bash conditional expressions. You do not have to
memorize them by heart. You can simply refer back to this list whenever you need it!
33
TELEGRAM: CODINIT( click here)
File expressions
[[ -a ${file} ]]
[[ -b ${file} ]]
[[ -c ${file} ]]
[[ -d ${file} ]]
[[ -e ${file} ]]
[[ -f ${file} ]]
[[ -h ${file} ]]
34
TELEGRAM: CODINIT( click here)
True if file exists and is readable.
[[ -r ${file} ]]
[[ -s ${file} ]]
[[ -w ${file} ]]
[[ -x ${file} ]]
[[ -L ${file} ]]
35
TELEGRAM: CODINIT( click here)
String expressions
True if the shell variable varname is set (has been assigned a value).
[[ -v ${varname} ]]
[[ -z ${string} ]]
[[ -n ${string} ]]
True if the strings are equal. = should be used with the test command for POSIX
conformance. When used with the [[ command, this performs pattern matching
as described above (Compound Commands).
[[ ${string1} == ${string2} ]]
[[ ${string1} != ${string2} ]]
36
TELEGRAM: CODINIT( click here)
37
TELEGRAM: CODINIT( click here)
Arithmetic operators
As with other programming languages you can use AND & OR conditions:
38
TELEGRAM: CODINIT( click here)
39
TELEGRAM: CODINIT( click here)
Exit status operators
returns true if the the command was successful without any errors
[[ $? -eq 0 ]]
returns true if the the command was not successful or had errors
[[ $? -gt 0 ]]
40
TELEGRAM: CODINIT( click here)
Bash Conditionals
In the last section, we covered some of the most popular conditional expressions. We
can now use them with standard conditional statements like if, if-else and
switch case statements.
41
TELEGRAM: CODINIT( click here)
If statement
if [[ some_test ]]
then
<commands>
fi
Here is a quick example which would ask you to enter your name in case that you've
left it empty:
#!/bin/bash
if [[ -z ${name} ]]
then
echo "Please enter your name!"
fi
42
TELEGRAM: CODINIT( click here)
If Else statement
With an if-else statement, you can specify an action in case that the condition in
the if statement does not match. We can combine this with the conditional
expressions from the previous section as follows:
#!/bin/bash
if [[ -z ${name} ]]
then
echo "Please enter your name!"
else
echo "Hi there ${name}"
fi
You can use the above if statement with all of the conditional expressions from the
previous chapters:
#!/bin/bash
admin="devdojo"
Here is another example of an if statement which would check your current User
ID and would not allow you to run the script as the root user:
43
TELEGRAM: CODINIT( click here)
#!/bin/bash
If you put this on top of your script it would exit in case that the EUID is 0 and would
not execute the rest of the script. This was discussed on the DigitalOcean community
forum.
You can also test multiple conditions with an if statement. In this example we want to
make sure that the user is neither the admin user or the root user to ensure the script
is incapable of causing too much damage. We'll use the or operator in this example,
noted by ||. This means that either of the conditions needs to be true. If we used the
and operator of && then both conditions would need to be true.
#!/bin/bash
admin="devdojo"
If you have multiple conditions and scenerios, then can use elif statement with if
and else statements.
44
TELEGRAM: CODINIT( click here)
#!/bin/bash
45
TELEGRAM: CODINIT( click here)
Switch case statements
As in other programming languages, you can use a case statement to simplify complex
conditionals when there are multiple different choices. So rather than using a few if,
and if-else statements, you could use a single case statement.
case $some_variable in
pattern_1)
commands
;;
pattern_2| pattern_3)
commands
;;
*)
default commands
;;
esac
46
TELEGRAM: CODINIT( click here)
#!/bin/bash
case $car in
Tesla)
echo -n "${car}'s car factory is in the USA."
;;
*)
echo -n "${car} is an unknown car brand"
;;
esac
With this script, we are asking the user to input a name of a car brand like Telsa,
BMW, Mercedes and etc.
Then with a case statement, we check the brand name and if it matches any of our
patterns, and if so, we print out the factory's location.
If the brand name does not match any of our case statements, we print out a default
message: an unknown car brand.
47
TELEGRAM: CODINIT( click here)
Conclusion
I would advise you to try and modify the script and play with it a bit so that you could
practice what you've just learned in the last two chapters!
For more examples of Bash case statements, make sure to check chapter 16, where
we would create an interactive menu in Bash using a cases statement to process the
user input.
48
TELEGRAM: CODINIT( click here)
Bash Loops
As with any other language, loops are very convenient. With Bash you can use for
loops, while loops, and until loops.
49
TELEGRAM: CODINIT( click here)
For loops
Example:
#!/bin/bash
First, we specify a list of users and store the value in a variable called $users.
After that, we start our for loop with the for keyword.
Then we define a new variable which would represent each item from the list
that we give. In our case, we define a variable called user, which would
represent each user from the $users variable.
Then we specify the in keyword followed by our list that we will loop through.
On the next line, we use the do keyword, which indicates what we will do for
each iteration of the loop.
Then we specify the commands that we want to run.
Finally, we close the loop with the done keyword.
You can also use for to process a series of numbers. For example here is one way to
loop through from 1 to 10:
50
TELEGRAM: CODINIT( click here)
#!/bin/bash
51
TELEGRAM: CODINIT( click here)
While loops
while [ your_condition ]
do
your_commands
done
#!/bin/bash
counter=1
while [[ $counter -le 10 ]]
do
echo $counter
((counter++))
done
First, we specified a counter variable and set it to 1, then inside the loop, we added
counter by using this statement here: ((counter++)). That way, we make sure that
the loop will run 10 times only and would not run forever. The loop will complete as
soon as the counter becomes 10, as this is what we've set as the condition: while [[
$counter -le 10 ]].
Let's create a script that asks the user for their name and not allow an empty input:
52
TELEGRAM: CODINIT( click here)
#!/bin/bash
while [[ -z ${name} ]]
do
echo "Your name can not be blank. Please enter a valid
name!"
read -p "Enter your name again? " name
done
Now, if you run the above and just press enter without providing input, the loop would
run again and ask you for your name again and again until you actually provide some
input.
53
TELEGRAM: CODINIT( click here)
Until Loops
The difference between until and while loops is that the until loop will run the
commands within the loop until the condition becomes true.
Structure:
until [[ your_condition ]]
do
your_commands
done
Example:
#!/bin/bash
count=1
until [[ $count -gt 10 ]]
do
echo $count
((count++))
done
54
TELEGRAM: CODINIT( click here)
Continue and Break
As with other languages, you can use continue and break with your bash scripts as
well:
continue tells your bash script to stop the current iteration of the loop and
start the next iteration.
continue [n]
The [n] argument is optional and can be greater than or equal to 1. When [n] is given,
the n-th enclosing loop is resumed. continue 1 is equivalent to continue.
#!/bin/bash
for i in 1 2 3 4 5
do
if [[ $i –eq 2 ]]
then
echo "skipping number 2"
continue
fi
echo "i is equal to $i"
done
We can also use continue command in similar way to break command for controlling
multiple loops.
break tells your bash script to end the loop straight away.
break [n]
[n] is an optional argument and must be greater than or equal to 1. When [n] is
provided, the n-th enclosing loop is exited. break 1 is equivalent to break.
55
TELEGRAM: CODINIT( click here)
Example:
#!/bin/bash
num=1
while [[ $num –lt 10 ]]
do
if [[ $num –eq 5 ]]
then
break
fi
((num++))
done
echo "Loop completed"
We can also use break command with multiple loops. If we want to exit out of current
working loop whether inner or outer loop, we simply use break but if we are in inner
loop & want to exit out of outer loop, we use break 2.
Example:
#!/bin/bash
The bash script will begin with a=1 & will move to inner loop and when it reaches b=5,
it will break the outer loop. We can use break only instead of break 2, to break inner
loop & see how it affects the output.
56
TELEGRAM: CODINIT( click here)
Bash Functions
Functions are a great way to reuse code. The structure of a function in bash is quite
similar to most languages:
function function_name() {
your_commands
}
You can also omit the function keyword at the beginning, which would also work:
function_name() {
your_commands
}
I prefer putting it there for better readability. But it is a matter of personal preference.
#!/bin/bash
function hello() {
echo "Hello World Function!"
}
hello
Notice: One thing to keep in mind is that you should not add the parenthesis
when you call the function.
57
TELEGRAM: CODINIT( click here)
#!/bin/bash
function hello() {
echo "Hello $1!"
}
hello DevDojo
#######################################
# Description: Hello function
# Globals:
# None
# Arguments:
# Single input argument
# Outputs:
# Value of input argument
# Returns:
# 0 if successful, non-zero on error.
#######################################
function hello() {
echo "Hello $1!"
}
58
TELEGRAM: CODINIT( click here)
In order to debug your bash scripts, you can use -x when executing your scripts:
bash -x ./your_script.sh
Or you can add set -x before the specific line that you want to debug, set -x
enables a mode of the shell where all executed commands are printed to the terminal.
Another way to test your scripts is to use this fantastic tool here:
https://www.shellcheck.net/
Just copy and paste your code into the textbox, and the tool will give you some
suggestions on how you can improve your script.
https://github.com/koalaman/shellcheck
If you like the tool, make sure to star it on GitHub and contribute!
The below two are particularly useful if you have a very long command.
Ctrl + k
59
TELEGRAM: CODINIT( click here)
Ctrl + u
Ctrl + w
Search your history backward. This is probably the one that I use the most. It is
really handy and speeds up my work-flow a lot:
Ctrl + r
Clear the screen, I use this instead of typing the clear command:
Ctrl + l
Ctrl + s
Enable the output to the screen in case that previously stopped by Ctrl + s:
Ctrl + q
Ctrl + c
60
TELEGRAM: CODINIT( click here)
Ctrl + z
If you think that I've missed any feel free to join the discussion on the DigitalOcean
community forum!
61
TELEGRAM: CODINIT( click here)
As a developer or system administrator, you might have to spend a lot of time in your
terminal. I always try to look for ways to optimize any repetitive tasks.
One way to do that is to either write short bash scripts or create custom commands
also known as aliases. For example, rather than typing a really long command every
time you could just create a short cut for it.
62
TELEGRAM: CODINIT( click here)
Example
Let's start with the following scenario, as a system admin, you might have to check the
connections to your web server quite often, so I will use the netstat command as an
example.
What I would usually do when I access a server that is having issues with the
connections to port 80 or 443 is to check if there are any services listening on those
ports and the number of connections to the ports.
The following netstat command would show us how many TCP connections on port
80 and 443 we currently have:
To avoid that, we can create an alias, so rather than typing the whole command, we
could just type a short command instead. For example, lets say that we wanted to be
able to type conn (short for connections) and get the same information. All we need to
do in this case is to run the following command:
That way we are creating an alias called conn which would essentially be a 'short cut'
for our long netstat command. Now if you run just conn:
conn
You would get the same output as the long netstat command. You can get even more
creative and add some info messages like this one here:
63
TELEGRAM: CODINIT( click here)
Now if you run conn you would get the following output:
Now if you log out and log back in, your alias would be lost. In the next step you will
see how to make this persistent.
64
TELEGRAM: CODINIT( click here)
Making the change persistent
In order to make the change persistent, we need to add the alias command in our
shell profile file.
By default on Ubuntu this would be the ~/.bashrc file, for other operating systems
this might be the ~/.bash_profle. With your favorite text editor open the file:
nano ~/.bashrc
That way now even if you log out and log back in again your change would be persisted
and you would be able to run your custom bash command.
65
TELEGRAM: CODINIT( click here)
Listing all of the available aliases
To list all of the available aliases for your current shell, you have to just run the
following command:
alias
This would be handy in case that you are seeing some weird behavior with some
commands.
66
TELEGRAM: CODINIT( click here)
Conclusion
Of course, you could actually write a bash script and add the script inside your
/usr/bin folder, but this would not work if you don't have root or sudo access,
whereas with aliases you can do it without the need of root access.
67
TELEGRAM: CODINIT( click here)
Let's try to put together what we've learned so far and create our first Bash script!
68
TELEGRAM: CODINIT( click here)
Planning the script
As an example, we will write a script that would gather some useful information about
our server like:
Feel free to adjust the script by adding or removing functionality so that it matches
your needs.
69
TELEGRAM: CODINIT( click here)
Writing the script
The first thing that you need to do is to create a new file with a .sh extension. I will
create a file called status.sh as the script that we will create would give us the
status of our server.
Once you've created the file, open it with your favorite text editor.
As we've learned in chapter 1, on the very first line of our Bash script we need to
specify the so-called Shebang:
#!/bin/bash
All that the shebang does is to instruct the operating system to run the script with the
/bin/bash executable.
70
TELEGRAM: CODINIT( click here)
Adding comments
Next, as discussed in chapter 6, let's start by adding some comments so that people
could easily figure out what the script is used for. To do that right after the shebang
you can just add the following:
#!/bin/bash
71
TELEGRAM: CODINIT( click here)
Adding your first variable
Then let's go ahead and apply what we've learned in chapter 4 and add some variables
which we might want to use throughout the script.
To assign a value to a variable in bash, you just have to use the = sign. For example,
let's store the hostname of our server in a variable so that we could use it later:
server_name=$(hostname)
By using $() we tell bash to actually interpret the command and then assign the value
to our variable.
Now if we were to echo out the variable we would see the current hostname:
echo $server_name
72
TELEGRAM: CODINIT( click here)
Adding your first function
As you already know after reading chapter 12, in order to create a function in bash you
need to use the following structure:
function function_name() {
your_commands
}
Let's create a function that returns the current memory usage on our server:
function memory_check() {
echo ""
echo "The current memory usage on ${server_name} is: "
free -h
echo ""
}
Then once the function has been defined, in order to call it, just use the name of the
function:
73
TELEGRAM: CODINIT( click here)
74
TELEGRAM: CODINIT( click here)
Adding more functions challenge
Before checking out the solution, I would challenge you to use the function from above
and write a few functions by yourself.
Feel free to use google if you are not sure what commands you need to use in order to
get that information.
Once you are ready, feel free to scroll down and check how we've done it and compare
the results!
75
TELEGRAM: CODINIT( click here)
The sample script
#!/bin/bash
##
# BASH script that checks:
# - Memory usage
# - CPU load
# - Number of TCP connections
# - Kernel version
##
server_name=$(hostname)
function memory_check() {
echo ""
echo "Memory usage on ${server_name} is: "
free -h
echo ""
}
function cpu_check() {
echo ""
echo "CPU load on ${server_name} is: "
echo ""
uptime
echo ""
}
function tcp_check() {
echo ""
echo "TCP connections on ${server_name}: "
echo ""
cat /proc/net/tcp | wc -l
echo ""
}
function kernel_check() {
echo ""
echo "Kernel version on ${server_name} is: "
echo ""
76
TELEGRAM: CODINIT( click here)
uname -r
echo ""
}
function all_checks() {
memory_check
cpu_check
tcp_check
kernel_check
}
all_checks
77
TELEGRAM: CODINIT( click here)
Conclusion
78
TELEGRAM: CODINIT( click here)
In this tutorial, I will show you how to create a multiple-choice menu in Bash so that
your users could choose between what action should be executed!
We would reuse some of the code from the previous chapter, so if you have not read it
yet make sure to do so.
79
TELEGRAM: CODINIT( click here)
Planning the functionality
Let's start again by going over the main functionality of the script:
In case that you don't have it on hand, here is the script itself:
#!/bin/bash
##
# BASH menu script that checks:
# - Memory usage
# - CPU load
# - Number of TCP connections
# - Kernel version
##
server_name=$(hostname)
function memory_check() {
echo ""
echo "Memory usage on ${server_name} is: "
free -h
echo ""
}
function cpu_check() {
echo ""
echo "CPU load on ${server_name} is: "
echo ""
uptime
echo ""
}
function tcp_check() {
echo ""
echo "TCP connections on ${server_name}: "
echo ""
cat /proc/net/tcp | wc -l
80
TELEGRAM: CODINIT( click here)
echo ""
}
function kernel_check() {
echo ""
echo "Kernel version on ${server_name} is: "
echo ""
uname -r
echo ""
}
function all_checks() {
memory_check
cpu_check
tcp_check
kernel_check
}
We will then build a menu that allows the user to choose which function to be
executed.
Of course, you can adjust the function or add new ones depending on your needs.
81
TELEGRAM: CODINIT( click here)
Adding some colors
In order to make the menu a bit more 'readable' and easy to grasp at first glance, we
will add some color functions.
##
# Color Variables
##
green='\e[32m'
blue='\e[34m'
clear='\e[0m'
##
# Color Functions
##
ColorGreen(){
echo -ne $green$1$clear
}
ColorBlue(){
echo -ne $blue$1$clear
}
The above would output the Some text here string and it would be blue!
82
TELEGRAM: CODINIT( click here)
Finally, to add our menu, we will create a separate function with a case switch for our
menu options:
menu(){
echo -ne "
My First Menu
$(ColorGreen '1)') Memory usage
$(ColorGreen '2)') CPU load
$(ColorGreen '3)') Number of TCP connections
$(ColorGreen '4)') Kernel version
$(ColorGreen '5)') Check All
$(ColorGreen '0)') Exit
$(ColorBlue 'Choose an option:') "
read a
case $a in
1) memory_check ; menu ;;
2) cpu_check ; menu ;;
3) tcp_check ; menu ;;
4) kernel_check ; menu ;;
5) all_checks ; menu ;;
0) exit 0 ;;
*) echo -e $red"Wrong option."$clear;
WrongCommand;;
esac
}
83
TELEGRAM: CODINIT( click here)
Then we read the answer of the user and store it in a variable called $a:
read a
Finally, we have a switch case which triggers a different function depending on the
value of $a:
case $a in
1) memory_check ; menu ;;
2) cpu_check ; menu ;;
3) tcp_check ; menu ;;
4) kernel_check ; menu ;;
5) all_checks ; menu ;;
0) exit 0 ;;
*) echo -e $red"Wrong option."$clear;
WrongCommand;;
esac
At the end we need to call the menu function to actually print out the menu:
84
TELEGRAM: CODINIT( click here)
Testing the script
#!/bin/bash
##
# BASH menu script that checks:
# - Memory usage
# - CPU load
# - Number of TCP connections
# - Kernel version
##
server_name=$(hostname)
function memory_check() {
echo ""
echo "Memory usage on ${server_name} is: "
free -h
echo ""
}
function cpu_check() {
echo ""
echo "CPU load on ${server_name} is: "
echo ""
uptime
echo ""
}
function tcp_check() {
echo ""
echo "TCP connections on ${server_name}: "
echo ""
cat /proc/net/tcp | wc -l
echo ""
}
function kernel_check() {
echo ""
echo "Kernel version on ${server_name} is: "
echo ""
85
TELEGRAM: CODINIT( click here)
uname -r
echo ""
}
function all_checks() {
memory_check
cpu_check
tcp_check
kernel_check
}
##
# Color Variables
##
green='\e[32m'
blue='\e[34m'
clear='\e[0m'
##
# Color Functions
##
ColorGreen(){
echo -ne $green$1$clear
}
ColorBlue(){
echo -ne $blue$1$clear
}
menu(){
echo -ne "
My First Menu
$(ColorGreen '1)') Memory usage
$(ColorGreen '2)') CPU load
$(ColorGreen '3)') Number of TCP connections
$(ColorGreen '4)') Kernel version
$(ColorGreen '5)') Check All
$(ColorGreen '0)') Exit
$(ColorBlue 'Choose an option:') "
read a
case $a in
1) memory_check ; menu ;;
2) cpu_check ; menu ;;
3) tcp_check ; menu ;;
4) kernel_check ; menu ;;
5) all_checks ; menu ;;
86
TELEGRAM: CODINIT( click here)
0) exit 0 ;;
*) echo -e $red"Wrong option."$clear;
WrongCommand;;
esac
}
To test the script, create a new filed with a .sh extension, for example: menu.sh and
then run it:
bash menu.sh
The output that you would get will look like this:
My First Menu
1) Memory usage
2) CPU load
3) Number of TCP connections
4) Kernel version
5) Check All
0) Exit
Choose an option:
You will be able to choose a different option from the list and each number will call a
different function from the script:
87
TELEGRAM: CODINIT( click here)
Conclusion
You now know how to create a Bash menu and implement it in your scripts so that
users could select different values!
88
TELEGRAM: CODINIT( click here)
Any command that you can run from the command line can be used in a bash script.
Scripts are used to run a series of commands. Bash is available by default on Linux and
macOS operating systems.
Let's have a hypothetical scenario where you need to execute a BASH script on
multiple remote servers, but you don't want to manually copy the script to each server,
then again login to each server individually and only then execute the script.
Of course you could use a tool like Ansible but lets learn how to do that with Bash!
89
TELEGRAM: CODINIT( click here)
Prerequisites
For this example I will use 3 remote Ubuntu servers deployed on DigitalOcean. If you
don't have a Digital Ocean account yet, you can sign up for DigitalOcean and get $100
free credit via this referral link here:
https://m.do.co/c/2a9bba940f39
Once you have your Digital Ocean account ready go ahead and deploy 3 droplets.
I'll put a those servers IP's in a servers.txt file which I would use to loop though
with our Bash script.
If you are new to DigitalOcean you can follow the steps on how to create a Droplet
here:
You can also follow the steps from this video here on how to do your initial server
setup:
Or even better, you can follow this article here on how to automate your initial server
setup with Bash:
With the 3 new servers in place, we can go ahead and focus on running our Bash script
on all of them with a single command!
90
TELEGRAM: CODINIT( click here)
The BASH Script
I will reuse the demo script from the previous chapter with some slight changes. It
simply executes a few checks like the current memory usage, the current CPU usage,
the number of TCP connections and the version of the kernel.
#!/bin/bash
##
# BASH script that checks the following:
# - Memory usage
# - CPU load
# - Number of TCP connections
# - Kernel version
##
##
# Memory check
##
server_name=$(hostname)
function memory_check() {
echo "#######"
echo "The current memory usage on ${server_name} is: "
free -h
echo "#######"
}
function cpu_check() {
echo "#######"
echo "The current CPU load on ${server_name} is: "
echo ""
uptime
echo "#######"
}
function tcp_check() {
echo "#######"
echo "Total TCP connections on ${server_name}: "
echo ""
cat /proc/net/tcp | wc -l
echo "#######"
91
TELEGRAM: CODINIT( click here)
}
function kernel_check() {
echo "#######"
echo "The exact Kernel version on ${server_name} is: "
echo ""
uname -r
echo "#######"
}
function all_checks() {
memory_check
cpu_check
tcp_check
kernel_check
}
all_checks
Copy the code bellow and add this in a file called remote_check.sh. You can also
get the script from here.
92
TELEGRAM: CODINIT( click here)
Running the Script on all Servers
Now that we have the script and the servers ready and that we've added those servers
in our servers.txt file we can run the following command to loop though all servers and
execute the script remotely without having to copy the script to each server and
individually connect to each server.
What this for loop does is, it goes through each server in the servers.txt file and then it
runs the following command for each item in the list:
93
TELEGRAM: CODINIT( click here)
Conclusion
This is just a really simple example on how to execute a simple script on multiple
servers without having to copy the script to each server and without having to access
the servers individually.
Of course you could run a much more complex script and on many more servers.
If you are interested in automation, I would recommend checking out the Ansible
resources page on the DigitalOcean website:
Ansible Resources
94
TELEGRAM: CODINIT( click here)
One of the great things about jq is that it is written in portable C, and it has zero
runtime dependencies. All you need to do is to download a single binary or use a
package manager like apt and install it with a single command.
95
TELEGRAM: CODINIT( click here)
Planning the script
For the demo in this tutorial, I would use an external REST API that returns a simple
JSON ouput called the QuizAPI:
https://quizapi.io/
If you want to follow along make sure to get a free API key here:
https://quizapi.io/clientarea/settings/token
96
TELEGRAM: CODINIT( click here)
Installing jq
There are many ways to install jq on your system. One of the most straight forward
ways to do so is to use the package manager depending on your OS.
Here is a list of the commands that you would need to use depending on your OS:
Install jq on Ubuntu/Debian:
Install jq on Fedora:
Install jq on openSUSE:
Install jq on Arch:
sudo pacman -S jq
brew install jq
port install jq
If you are using other OS, I would recommend taking a look at the official
97
TELEGRAM: CODINIT( click here)
documentation here for more information:
https://stedolan.github.io/jq/download/
Once you have jq installed you can check your current version by running this
command:
jq --version
98
TELEGRAM: CODINIT( click here)
Parsing JSON with jq
Once you have jq installed and your QuizAPI API Key, you can parse the JSON output
of the QuizAPI directly in your terminal.
API_KEY=YOUR_API_KEY_HERE
In order to get some output from one of the endpoints of the QuizAPI you can use the
curl command:
curl
"https://quizapi.io/api/v1/questions?apiKey=${API_KEY}&limit=1
0"
For a more specific output, you can use the QuizAPI URL Generator here:
https://quizapi.io/api-config
After running the curl command, the output which you would get would look like this:
This could be quite hard to read, but thanks to the jq command-line tool, all we need to
do is pipe the curl command to jq and we would see a nice formated JSON output:
curl
"https://quizapi.io/api/v1/questions?apiKey=${API_KEY}&limit=1
0" | jq
In this case the output that you would get would look something like this:
Now, this looks much nicer! The jq command-line tool formatted the output for us and
99
TELEGRAM: CODINIT( click here)
added some nice coloring!
100
TELEGRAM: CODINIT( click here)
Getting the first element with jq
Let's say that we only wanted to get the first element from the JSON output, in order to
do that we have to just specify the index that we want to see with the following syntax:
jq .[0]
Now, if we run the curl command again and pipe the output to jq .[0] like this:
curl
"https://quizapi.io/api/v1/questions?apiKey=${API_KEY}&limit=1
0" | jq.[0]
You will only get the first element and the output will look like this:
101
TELEGRAM: CODINIT( click here)
Getting a value only for specific key
Sometimes you might want to get only the value of a specific key only, let's say in our
example the QuizAPI returns a list of questions along with the answers, description and
etc. but what if you wanted to get the Questions only without the additional
information?
This is going to be quite straight forward with jq, all you need to do is add the key
after jq command, so it would look something like this:
jq .[].question
We have to add the .[] as the QuizAPI returns an array and by specifying .[] we tell
jq that we want to get the .question value for all of the elements in the array.
The output that you would get would look like this:
As you can see we now only get the questions without the rest of the values.
102
TELEGRAM: CODINIT( click here)
Using jq in a BASH script
Let's go ahead and create a small bash script which should output the following
information for us:
Notice: make sure to change the API_KEY part with your actual QuizAPI key:
103
TELEGRAM: CODINIT( click here)
#!/bin/bash
##
# Make an API call to QuizAPI and store the output in a
variable
##
output=$(curl
'https://quizapi.io/api/v1/questions?apiKey=API_KEY&limit=10'
2>/dev/null)
##
# Get only the first question
##
output=$(echo $output | jq .[0])
##
# Get the question
##
question=$(echo $output | jq .question)
##
# Get the answers
##
##
# Output the question
##
echo "
Question: ${question}
A) ${answer_a}
B) ${answer_b}
C) ${answer_c}
D) ${answer_d}
"
If you run the script you would get the following output:
104
TELEGRAM: CODINIT( click here)
We can even go further by making this interactive so that we could actually choose the
answer directly in our terminal.
There is already a bash script that does this by using the QuizAPI and jq:
https://github.com/QuizApi/QuizAPI-BASH/blob/master/quiz.sh
105
TELEGRAM: CODINIT( click here)
Conclusion
The jq command-line tool is an amazing tool that gives you the power to work with
JSON directly in your BASH terminal.
That way you can easily interact with all kinds of different REST APIs with BASH.
For more information, you could take a look at the official documentation here:
https://stedolan.github.io/jq/manual/
And for more information on the QuizAPI, you could take a look at the official
documentation here:
https://quizapi.io/docs/1.0/overview
106
TELEGRAM: CODINIT( click here)
My personal favorite Cloudflare feature is their free DDoS protection. It has saved my
servers multiple times from different DDoS attacks. They have a cool API that you
could use to enable and disable their DDoS protection easily.
This chapter is going to be an exercise! I challenge you to go ahead and write a short
bash script that would enable and disable the Cloudflare DDoS protection for your
server automatically if needed!
107
TELEGRAM: CODINIT( click here)
Prerequisites
Before following this guide here, please set up your Cloudflare account and get your
website ready. If you are not sure how to do that you can follow these steps here:
Create a Cloudflare account and add a website.
Once you have your Cloudflare account, make sure to obtain the following information:
A Cloudflare account
Cloudflare API key
Cloudflare Zone ID
curl --version
For RedHat/CentOs:
For Debian/Ubuntu
108
TELEGRAM: CODINIT( click here)
Challenge - Script requirements
The script needs to monitor the CPU usage on your server and if the CPU usage gets
high based on the number vCPU it would enable the Cloudflare DDoS protection
automatically via the Cloudflare API.
109
TELEGRAM: CODINIT( click here)
Example script
I already have prepared a demo script which you could use as a reference. But I
encourage you to try and write the script yourself first and only then take a look at my
script!
wget
https://raw.githubusercontent.com/bobbyiliev/cloudflare-ddos-p
rotection/main/protection.sh
nano protection.sh
CF_CONE_ID=YOUR_CF_ZONE_ID
CF_EMAIL_ADDRESS=YOUR_CF_EMAIL_ADDRESS
CF_API_KEY=YOUR_CF_API_KEY
chmod +x ~/protection.sh
Finally, set up 2 Cron jobs to run every 30 seconds. To edit your crontab run:
crontab -e
110
TELEGRAM: CODINIT( click here)
* * * * * /path-to-the-script/cloudflare/protection.sh
* * * * * ( sleep 30 ; /path-to-the-
script/cloudflare/protection.sh )
Note that you need to change the path to the script with the actual path where you've
stored the script at.
111
TELEGRAM: CODINIT( click here)
Conclusion
This is quite straight forward and budget solution, one of the downsides of the script is
that if your server gets unresponsive due to an attack, the script might not be triggered
at all.
Of course, a better approach would be to use a monitoring system like Nagios and
based on the statistics from the monitoring system then you can trigger the script, but
this script challenge could be a good learning experience!
Here is another great resource on how to use the Discord API and send notifications to
your Discord Channel with a Bash script:
How To Use Discord Webhooks to Get Notifications for Your Website Status on Ubuntu
18.04
112
TELEGRAM: CODINIT( click here)
One of the first things that I would usually do in case I notice a high CPU usage on
some of my Linux servers would be to check the process list with either top or htop and
in case that I notice a lot of Apache or Nginx process I would quickly check my access
logs to determine what has caused or is causing the CPU spike on my server or to
figure out if anything malicious is going on.
Sometimes reading the logs could be quite intimidating as the log might be huge and
going though it manually could take a lot of time. Also, the raw log format could be
confusing for people with less experience.
Just like the previous chapter, this chapter is going to be a challenge! You need to
write a short bash script that would summarize the whole access log for you without
the need of installing any additional software.
113
TELEGRAM: CODINIT( click here)
Script requirements
This BASH script needs to parse and summarize your access logs and provide you with
very useful information like:
114
TELEGRAM: CODINIT( click here)
Example script
I already have prepared a demo script which you could use as a reference. But I
encourage you to try and write the script yourself first and only then take a look at my
script!
In order to download the script, you can either clone the repository with the following
command:
git clone
https://github.com/bobbyiliev/quick_access_logs_summary.git
Or run the following command which would download the script in your current
directory:
wget
https://raw.githubusercontent.com/bobbyiliev/quick_access_logs
_summary/master/spike_check
The script does not make any changes to your system, it only reads the content of your
access log and summarizes it for you, however, once you've downloaded the file, make
sure to review the content yourself.
115
TELEGRAM: CODINIT( click here)
Running the script
All that you have to do once the script has been downloaded is to make it executable
and run it.
chmod +x spike_check
./spike_check /path/to/your/access_log
Make sure to change the path to the file with the actual path to your access log. For
example if you are using Apache on an Ubuntu server, the exact command would look
like this:
./spike_check /var/log/apache2/access.log
If you are using Nginx the exact command would be almost the same, but with the path
to the Nginx access log:
./spike_check /var/log/nginx/access.log
116
TELEGRAM: CODINIT( click here)
Understanding the output
Once you run the script, it might take a while depending on the size of the log.
The output that you would see should look like this:
Essentially what we can tell in this case is that we've received 16 POST requests to our
xmlrpc.php file which is often used by attackers to try and exploit WordPress websites
by using various username and password combinations.
In this specific case, this was not a huge brute force attack, but it gives us an early
indication and we can take action to prevent a larger attack in the future.
We can also see that there were a couple of Russian IP addresses accessing our site, so
in case that you do not expect any traffic from Russia, you might want to block those IP
addresses as well.
117
TELEGRAM: CODINIT( click here)
Conclusion
This is an example of a simple BASH script that allows you to quickly summarize your
access logs and determine if anything malicious is going on.
Of course, you might want to also manually go through the logs as well but it is a good
challenge to try and automate this with Bash!
118
TELEGRAM: CODINIT( click here)
SSMTP is a tool that delivers emails from a computer or a server to a configured mail
host.
SSMTP is not an email server itself and does not receive emails or manage a queue.
One of its primary uses is for forwarding automated email (like system alerts) off your
machine and to an external email address.
119
TELEGRAM: CODINIT( click here)
Prerequisites
You would need the following things in order to be able to complete this tutorial
successfully:
Access to an Ubuntu 18.04 server as a non-root user with sudo privileges and an
active firewall installed on your server. To set these up, please refer to our Initial
Server Setup Guide for Ubuntu 18.04
An SMTP server along with SMTP username and password, this would also work
with Gmail's SMTP server, or you could set up your own SMTP server by
following the steps from this tutorial on
[https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-
postfix-as-a-send-only-smtp-server-on-ubuntu-16-04](How to Install and
Configure Postfix as a Send-Only SMTP Server on Ubuntu 16.04)
120
TELEGRAM: CODINIT( click here)
Installing SSMTP
In order to install SSMTP, you’ll need to first update your apt cache with:
Another thing that you would need to install is mailutils, to do that run the
following command:
121
TELEGRAM: CODINIT( click here)
Configuring SSMTP
Now that you have ssmtp installed, in order to configure it to use your SMTP server
when sending emails, you need to edit the SSMTP configuration file.
root=postmaster
mailhub=<^>your_smtp_host.com<^>:587
hostname=<^>your_hostname<^>
AuthUser=<^>your_gmail_username@your_smtp_host.com<^>
AuthPass=<^>your_gmail_password<^>
FromLineOverride=YES
UseSTARTTLS=YES
122
TELEGRAM: CODINIT( click here)
Sending emails with SSMTP
Once your configuration is done, in order to send an email just run the following
command:
You can run this directly in your terminal or include it in your bash scripts.
123
TELEGRAM: CODINIT( click here)
Sending A File with SSMTP (optional)
Next, in order to send an email with a file attached, run the following command.
124
TELEGRAM: CODINIT( click here)
Conclusion
SSMTP is a great and reliable way to implement SMTP email functionality directly in
bash scripts.
For more information about SSMTP I would recommend checking the official
documentation here.
Notice: This content was initially posted on the DigitalOcean community forum.
125
TELEGRAM: CODINIT( click here)
It's not uncommon situation where you will need to generate a random password that
you can use for any software installation or when you sign-up to any website.
There are a lot of options in order to achieve this. You can use a password
manager/vault where you often have the option to randomly generate a password or to
use a website that can generate the password on your behalf.
You can also use Bash in your terminal (command-line) to generate a password that
you can quickly use. There are a lot of ways to achieve that and I will make sure to
cover few of them and will leave up to you to choose which option is most suitable with
your needs.
126
TELEGRAM: CODINIT( click here)
:warning: Security
This script is intended to practice your bash scripting skills. You can have fun
while doing simple projects with BASH, but security is not a joke, so please
make sure you do not save your passwords in plain text in a local file or write
them down by hand on a piece of paper.
127
TELEGRAM: CODINIT( click here)
Script summary
1. We will have to option to choose the password characters length when the script
is executed.
2. The script will then generate 5 random passwords with the length that was
specified in step 1
128
TELEGRAM: CODINIT( click here)
Prerequisites
You would need a bash terminal and a text editor. You can use any text editor like vi,
vim, nano or Visual Studio Code.
I'm running the script locally on my Linux laptop but if you're using Windows PC you
can ssh to any server of your choice and execute the script there.
Although the script is pretty simple, having some basic BASH scripting knowledge will
help you to better understand the script and how it's working.
129
TELEGRAM: CODINIT( click here)
Generate a random password
One of the great benefits of Linux is that you can do a lot of things using different
methods. When it comes to generating a random string of characters it's not different
as well.
You can use several commands in order to generate a random string of characters. I
will cover few of them and will provide some examples.
Using the date command. The date command will output the current date and
time. However we also further manipulate the output in order to use it as
randomly generated password. We can hash the date using md5, sha or just run
it through base64. These are few examples:
date | md5sum
94cb1cdecfed0699e2d98acd9a7b8f6d -
using sha256sum:
date | sha256sum
30a0c6091e194c8c7785f0d7bb6e1eac9b76c0528f02213d1b6a5fbcc76cef
f4 -
using base64:
date | base64
0YHQsSDRj9C90YMgMzAgMTk6NTE6NDggRUVUIDIwMjEK
We can also use openssl in order to generate pseudo-random bytes and run the
output through base64. An example output will be:
Keep in mind that openssl might not be installed on your system so it's likely that you
will need to install it first in order to use it.
130
TELEGRAM: CODINIT( click here)
The most preferred way is to use the pseudorandom number generator -
/dev/urandom since it is intended for most cryptographic purposes. We would
also need to manipulate the output using tr in order to translate it. An example
command is:
With this command we take the output from /dev/urandom and translate it with tr
while using all letters and digits and print the desired number of characters.
131
TELEGRAM: CODINIT( click here)
The script
First we begin the script with the shebang. We use it to tell the operating system which
interpreter to use to parse the rest of the file.
#!/bin/bash
We can then continue and ask the user for some input. In this case we would like to
know how many characters the password needs to be:
Generate the passwords and then print it so the user can use it.
132
TELEGRAM: CODINIT( click here)
The full script:
#!/bin/bash
#=======================================
# Password generator with login option
#=======================================
133
TELEGRAM: CODINIT( click here)
Conclusion
This is pretty much how you can use simple bash script to generate random passwords.
While the script is working fine, it expects that the user will provide the requested
input. In order to prevent any issues you would need to do some more advance checks
on the user input in order to make sure the script will continue to work fine even if the
provided input does not match our needs.
134
TELEGRAM: CODINIT( click here)
Contributed by
Alex Georgiev
135
TELEGRAM: CODINIT( click here)
Redirection in Bash
A Linux superuser must have a good knowledge of pipes and redirection in Bash. It is
an essential component of the system and is often helpful in the field of Linux System
Administration.
When you run a command like ls, cat, etc, you get some output on the terminal. If
you write a wrong command, pass a wrong flag or a wrong command-line argument,
you get error output on the terminal. In both the cases, you are given some text. It may
seem like "just text" to you, but the system treats this text differently. This identifier is
known as a File Descriptor (fd).
In Linux, there are 3 File Descriptors, STDIN (0); STDOUT (1) and STDERR (2).
136
TELEGRAM: CODINIT( click here)
Both pipes and redidertions redirect streams (file descriptor) of process being
executed. The main diffrence is that redirections deal with files stream, sending
the output stream to a file or sending the content of a given file to the input stream of
the process.
On the otherhand a pipe connects two commands by sending the output stream of the
first one to the input stream of the second one. without any redidertions specified.
137
TELEGRAM: CODINIT( click here)
Redirection in Bash
138
TELEGRAM: CODINIT( click here)
STDIN (Standard Input)
When you enter some input text for a command that asks for it, you are actually
entering the text to the STDIN file descriptor. Run the cat command without any
command-line arguments. It may seem that the process has paused but in fact it's cat
asking for STDIN. cat is a simple program and will print the text passed to STDIN.
However, you can extend the use case by redirecting the input to the commands that
take STDIN.
This will simply print the provided text on the terminal screen:
Hello World!
How are you?
The same can be done with other commands that take input via STDIN. Like, wc:
wc -l << EOF
Hello World!
How are you?
EOF
The -l flag with wc counts the number of lines. This block of bash code will print the
number of lines to the terminal screen:
139
TELEGRAM: CODINIT( click here)
STDOUT (Standard Output)
The normal non-error text on your terminal screen is printed via the STDOUT file
descriptor. The STDOUT of a command can be redirected into a file, in such a way that
the output of the command is written to a file instead of being printed on the terminal
screen. This is done simply with the help of > and >> operators.
Example:
The following command will not print "Hello World" on the terminal screen, it will
instead create a file called file.txt and will write the "Hello World" string to it. This
can be verified by runnning the cat command on the file.txt file.
cat file.txt
However, everytime you redirect the STDOUT of any command multiple times to the
same file, it will remove the existing contents of the file to write the new ones.
Example:
cat file.txt
You will only get the "How are you?" string printed.
This is because the "Hello World" string has been overwritten. This behaviour can be
140
TELEGRAM: CODINIT( click here)
avoided using the >> operator.
On running cat on the file.txt file, you will get the desired result.
Hello World!
How are you?
Alternatively, the redirection operator for STDOUT can also be written as 1>. Like,
141
TELEGRAM: CODINIT( click here)
STDERR (Standard Error)
The error text on the terminal screen is printed via the STDERR of the the command.
For example:
ls --hello
would give an error messages. This error message is the STDERR of the command.
This command will redirect the error message to the error.txt file and write it to it.
This can be verified by running the cat command on the error.txt file.
You can also use the 2>> operator for STDERR just like you used >> for STDOUT.
Error messages in Bash Scripts can be undesirable sometimes. You can choose to
ignore them by redirecting the error message to the /dev/null file. /dev/null is
pseudo-device that takes in text and then immediately discards it.
The above example can be written follows to ignore the error text completely:
Of course, you can redirect both STDOUT and STDERR for the same command or
script.
142
TELEGRAM: CODINIT( click here)
143
TELEGRAM: CODINIT( click here)
Piping
So far we have seen how to redirect the STDOUT, STDIN and STDOUT to and from a
file. To concatenate the output of program (command) as the input of another program
(command) you can use a vertical bar |.
Example:
ls | grep ".txt"
This command will list the files in the current directory and pass output to grep
command which then filter the output to only show the files that contain the string
".txt".
Syntax:
You can also build arbitrary chains of commands by piping them together to achieve a
powerful result.
This examble create a listing of every user which owns a file in a given directory as
well as how many files and directories they own:
Output:
144
TELEGRAM: CODINIT( click here)
8 anne
34 harry
37 tina
18 ryan
145
TELEGRAM: CODINIT( click here)
HereDocument
The symbol << can be used to create a temporary file [heredoc] and redirect from it at
the command line.
Note here that EOF represents the delimiter (end of file) of the heredoc. In fact, we can
use any alphanumeric word in it's place to signify the start and the end of the file. For
instance, this is a valid heredoc:
Effectively it will appear as if the contents of the heredoc are piped into the command.
This can make the script very clean if multiple lines need to be piped into a program.
146
TELEGRAM: CODINIT( click here)
147
TELEGRAM: CODINIT( click here)
HereString
Herestrings are quite similar to heredocs but use <<<. These are used for single line
strings that have to be piped into some program. This looks cleaner that heredocs as
we don't have to specify the delimiter.
148
TELEGRAM: CODINIT( click here)
Summary
Operator Description
> Save output to a file
>> Append output to a file
< Read input from a file
2> Redirect error messages
Send the output from one program as input to another
|
program
<< Pipe multiple lines into a program cleanly
<<< Pipe a single line into a program cleanly
149
TELEGRAM: CODINIT( click here)
Automatic Wordpress on
LAMP installation with BASH
Here is an example of a full LAMP and Wordpress installation that works on any
Debian-based machine.
150
TELEGRAM: CODINIT( click here)
Prerequisites
151
TELEGRAM: CODINIT( click here)
Let's start again by going over the main functionality of the script:
Lamp Installation
SSL Config
Database Config
Create a database
Create a user
Flush Privileges
Wordpress Config
152
TELEGRAM: CODINIT( click here)
Append the required information to wp-config.php file
153
TELEGRAM: CODINIT( click here)
The script
We start by setting our variables and asking the user to input their domain:
We are now ready to start writing our functions. Start by creating the
lamp_install() function. Inside of it, we are going to update the system, install
ufw, allow SSH, HTTP and HTTPS traffic, install Apache2, install MariaDB and PHP.
We are also going to enable all required Apache2 mods.
154
TELEGRAM: CODINIT( click here)
lamp_install () {
apt update -y
apt install ufw
ufw enable
ufw allow OpenSSH
ufw allow in "WWW Full"
155
TELEGRAM: CODINIT( click here)
apache_virtual_host_setup () {
mkdir /var/www/$DOMAIN
chown -R $USER:$USER /var/www/$DOMAIN
Next, we are going to create the ssl_config() function. Inside of it, we are going to
generate the OpenSSL certificate, append the SSL certificate to the ssl-
params.conf file, append the SSL config to the Virtualhost file, enable SSL and
reload Apache2.
ssl_config () {
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -
keyout /etc/ssl/private/apache-selfsigned.key -out
/etc/ssl/certs/apache-selfsigned.crt
echo "SSLCipherSuite
EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH" >>
/etc/apache2/conf-available/ssl-params.conf
echo "SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1"
>> /etc/apache2/conf-available/ssl-params.conf
echo "SSLHonorCipherOrder On" >> /etc/apache2/conf-
available/ssl-params.conf
echo "Header always set X-Frame-Options DENY" >>
156
TELEGRAM: CODINIT( click here)
/etc/apache2/conf-available/ssl-params.conf
echo "Header always set X-Content-Type-Options
nosniff" >> /etc/apache2/conf-available/ssl-params.conf
echo "SSLCompression off" >> /etc/apache2/conf-
available/ssl-params.conf
echo "SSLUseStapling on" >> /etc/apache2/conf-
available/ssl-params.conf
echo "SSLStaplingCache \"shmcb:logs/stapling-
cache(150000)\"" >> /etc/apache2/conf-available/ssl-
params.conf
echo "SSLSessionTickets Off" >> /etc/apache2/conf-
available/ssl-params.conf
cp /etc/apache2/sites-available/default-ssl.conf
/etc/apache2/sites-available/default-ssl.conf.bak
sed -i "s/var\/www\/html/var\/www\/$DOMAIN/1"
/etc/apache2/sites-available/default-ssl.conf
sed -i "s/etc\/ssl\/certs\/ssl-cert-
snakeoil.pem/etc\/ssl\/certs\/apache-selfsigned.crt/1"
/etc/apache2/sites-available/default-ssl.conf
sed -i "s/etc\/ssl\/private\/ssl-cert-
snakeoil.key/etc\/ssl\/private\/apache-selfsigned.key/1"
/etc/apache2/sites-available/default-ssl.conf
sed -i "4i\\\t\tServerName $ip" /etc/apache2/sites-
available/default-ssl.conf
sed -i "22i\\\tRedirect permanent \"/\"
\"https://$ip/\"" /etc/apache2/sites-available/000-
default.conf
a2enmod ssl
a2enmod headers
a2ensite default-ssl
a2enconf ssl-params
systemctl reload apache2
}
Next, we are going to create the db_setup() function. Inside of it, we are going to
create the database, create the user and grant all privileges to the user.
157
TELEGRAM: CODINIT( click here)
db_config () {
mysql -e "CREATE DATABASE $DBNAME;"
mysql -e "GRANT ALL ON $DBNAME.* TO
'$DBUSERNAME'@'localhost' IDENTIFIED BY '$DBPASSWORD' WITH
GRANT OPTION;"
mysql -e "FLUSH PRIVILEGES;"
}
Next, we are going to create the wordpress_config() function. Inside of it, we are
going to download the latest version of WordPress, extract it to the
/var/www/$DOMAIN directory, create the wp-config.php file and append the
required content to it.
158
TELEGRAM: CODINIT( click here)
wordpress_config () {
db_config
a2enmod rewrite
systemctl restart apache2
And finally, we are going to create the execute() function. Inside of it, we are going
to call all the functions we created above.
159
TELEGRAM: CODINIT( click here)
execute () {
lamp_install
apache_virtual_host_setup
ssl_config
wordpress_config
}
With this, you have the script ready and you are ready to run it. And if you need the full
script, you can find it in the next section.
160
TELEGRAM: CODINIT( click here)
#!/bin/bash
lamp_install () {
apt update -y
apt install ufw
ufw enable
ufw allow OpenSSH
ufw allow in "WWW Full"
apache_virtual_host_setup () {
mkdir /var/www/$DOMAIN
chown -R $USER:$USER /var/www/$DOMAIN
161
TELEGRAM: CODINIT( click here)
available/$DOMAIN.conf
echo -e "\tServerAlias www.$DOMAIN" >>
/etc/apache2/sites-available/$DOMAIN.conf
echo -e "\tServerAdmin webmaster@localhost" >>
/etc/apache2/sites-available/$DOMAIN.conf
echo -e "\tDocumentRoot /var/www/$DOMAIN" >>
/etc/apache2/sites-available/$DOMAIN.conf
echo -e '\tErrorLog ${APACHE_LOG_DIR}/error.log' >>
/etc/apache2/sites-available/$DOMAIN.conf
echo -e '\tCustomLog ${APACHE_LOG_DIR}/access.log
combined' >> /etc/apache2/sites-available/$DOMAIN.conf
echo "</VirtualHost>" >> /etc/apache2/sites-
available/$DOMAIN.conf
a2ensite $DOMAIN
a2dissite 000-default
systemctl reload apache2
ssl_config () {
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -
keyout /etc/ssl/private/apache-selfsigned.key -out
/etc/ssl/certs/apache-selfsigned.crt
echo "SSLCipherSuite
EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH" >>
/etc/apache2/conf-available/ssl-params.conf
echo "SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1"
>> /etc/apache2/conf-available/ssl-params.conf
echo "SSLHonorCipherOrder On" >> /etc/apache2/conf-
available/ssl-params.conf
echo "Header always set X-Frame-Options DENY" >>
/etc/apache2/conf-available/ssl-params.conf
echo "Header always set X-Content-Type-Options
nosniff" >> /etc/apache2/conf-available/ssl-params.conf
echo "SSLCompression off" >> /etc/apache2/conf-
available/ssl-params.conf
echo "SSLUseStapling on" >> /etc/apache2/conf-
available/ssl-params.conf
echo "SSLStaplingCache \"shmcb:logs/stapling-
cache(150000)\"" >> /etc/apache2/conf-available/ssl-
params.conf
echo "SSLSessionTickets Off" >> /etc/apache2/conf-
available/ssl-params.conf
cp /etc/apache2/sites-available/default-ssl.conf
/etc/apache2/sites-available/default-ssl.conf.bak
162
TELEGRAM: CODINIT( click here)
sed -i "s/var\/www\/html/var\/www\/$DOMAIN/1"
/etc/apache2/sites-available/default-ssl.conf
sed -i "s/etc\/ssl\/certs\/ssl-cert-
snakeoil.pem/etc\/ssl\/certs\/apache-selfsigned.crt/1"
/etc/apache2/sites-available/default-ssl.conf
sed -i "s/etc\/ssl\/private\/ssl-cert-
snakeoil.key/etc\/ssl\/private\/apache-selfsigned.key/1"
/etc/apache2/sites-available/default-ssl.conf
sed -i "4i\\\t\tServerName $ip" /etc/apache2/sites-
available/default-ssl.conf
sed -i "22i\\\tRedirect permanent \"/\"
\"https://$ip/\"" /etc/apache2/sites-available/000-
default.conf
a2enmod ssl
a2enmod headers
a2ensite default-ssl
a2enconf ssl-params
systemctl reload apache2
}
db_config () {
mysql -e "CREATE DATABASE $DBNAME;"
mysql -e "GRANT ALL ON $DBNAME.* TO
'$DBUSERNAME'@'localhost' IDENTIFIED BY '$DBPASSWORD' WITH
GRANT OPTION;"
mysql -e "FLUSH PRIVILEGES;"
}
wordpress_config () {
db_config
a2enmod rewrite
systemctl restart apache2
163
TELEGRAM: CODINIT( click here)
tar xzvf latest.tar.gz
touch /tmp/wordpress/.htaccess
cp /tmp/wordpress/wp-config-sample.php
/tmp/wordpress/wp-config.php
mkdir /tmp/wordpress/wp-content/upgrade
cp -a /tmp/wordpress/. /var/www/$DOMAIN
chown -R www-data:www-data /var/www/$DOMAIN
find /var/www/$DOMAIN/ -type d -exec chmod 750 {} \;
find /var/www/$DOMAIN/ -type f -exec chmod 640 {} \;
curl -s https://api.wordpress.org/secret-key/1.1/salt/
>> /var/www/$DOMAIN/wp-config.php
echo "define('FS_METHOD', 'direct');" >>
/var/www/$DOMAIN/wp-config.php
sed -i "51,58d" /var/www/$DOMAIN/wp-config.php
sed -i "s/database_name_here/$DBNAME/1"
/var/www/$DOMAIN/wp-config.php
sed -i "s/username_here/$DBUSERNAME/1"
/var/www/$DOMAIN/wp-config.php
sed -i "s/password_here/$DBPASSWORD/1"
/var/www/$DOMAIN/wp-config.php
}
execute () {
lamp_install
apache_virtual_host_setup
ssl_config
wordpress_config
}
164
TELEGRAM: CODINIT( click here)
Summary
Install LAMP
Create a virtual host
Configure SSL
Install WordPress
Configure WordPress
With this being said, I hope you enjoyed this example. If you have any questions, please
feel free to ask me directly at @denctl.
165
TELEGRAM: CODINIT( click here)
Wrap Up
If you have any suggestions for improvements, make sure to contribute pull requests or
open issues.
In this introduction to Bash scripting book, we just covered the basics, but you still
have enough under your belt to start wringing some awesome scripts and automating
daily tasks!
As a next step try writing your own script and share it with the world! This is the best
way to learn any new programming or scripting language!
In case that this book enspired you to write some cool Bash scripts, make sure to tweet
about it and tag @bobbyiliev_ so that we could check it out!
166