Bash (Bourne-Again SHell) is a command interpreter in UNIX-like operating systems that allows for task automation at the command line level. Bash scripts are files containing a sequence of commands that can be executed by the Bash interpreter.
Bash scripts can be used to automate repetitive tasks. For example, if you need to generate and send a report via email every day, you can write a bash script that performs these actions automatically. This saves a lot of time and reduces the likelihood of errors.
In this article, we will cover the basic concepts and tools for writing Bash scripts in Linux.
Bash scripts can be written in any text editor and must have executable permissions. Let’s consider some of the most popular editors:
Nano is a simple text editor that comes with most Linux distributions. It has an intuitive interface and useful features like syntax highlighting.
Vim is one of the most popular text editors for Linux, though it may seem complicated for beginners. Vim offers many features to speed up coding, such as syntax highlighting, autocompletion, and macros.
Emacs is another popular text editor for Linux. It also has many features that can simplify the coding process. One of its main features is the ability to run the Bash interpreter inside the editor, allowing you to test scripts without exiting the editor.
At the beginning of each script, there must be a line called a shebang, which tells the operating system which interpreter to use to execute the script. The shebang should start with a hash symbol (#
) followed by an exclamation mark (!
), and then the path to the interpreter. To use the Bash interpreter, the shebang will look like this:
#!/bin/bash
While writing the script, you can also leave comments that start with a hash symbol and continue until the end of the line. Comments will not be executed by the interpreter and are used to describe the functionality of the script. For example:
# This is a comment
Below, we will write our first script. Suppose we want to create a script in Linux that greets the user and displays the current date and time on the screen. To do this, create a file named greeting.sh
in any directory on your computer and add the following code:
#!/bin/bash
echo "Hello, $USER!"
echo "Today is $(date)"
The first line indicates that this is a Bash script. The next line, echo "Hello $USER!"
, outputs a greeting with the current user's name. $USER
is a system variable that contains the name of the current user. The third line, echo "Today is $(date)"
, displays the current date and time. $(date)
is used to call the date
command, which returns the current date and time in the system's format.
When creating a Bash script, it’s important to ensure the file is executable. To do this, you need to change the file permissions. We’ll cover this and how to run the script in the next chapter.
To run a script in Linux, it must have executable permissions. To make a file executable, you can use the chmod command (short for "change mode"). This command allows you to change the access permissions of files and directories in Linux.
The syntax for the chmod
command is as follows:
chmod [options] access_rights file
where access_rights
is a special code that sets the access permissions for a file or directory, and file
is the path to the file or directory whose permissions you want to change.
To make a file executable, you need to add the execute (x
) permission to its access rights. For example, to make the greeting.sh
file executable, use the following command:
chmod +x greeting.sh
This command will add execute permissions for the current user. Now, we can run the Bash script in Linux by invoking it from the terminal:
./greeting.sh
The result of running the script is shown below.
Command line parameters allow you to pass arguments to Linux scripts when they are run. Command line parameters can be accessed in the script as $1
, $2
, $3
, etc., where $1
is the first parameter, $2
is the second parameter, and so on.
Let's rewrite the script from the previous chapter to greet the user using a command-line argument:
#!/bin/bash
echo "Hello $1!"
Then run the script, passing the $USER
argument:
./greeting.sh $USER
The result is shown below.
Additionally, you can use special command line parameters:
$0
— the name of the script (i.e., the name of the file that was run)
$#
— the number of passed parameters
$*
or $@
— a list of all passed parameters (as a single string or array, respectively)
$?
— the return code of the last executed command
For example, to display the number of passed parameters, you can use the following code:
#!/bin/bash
echo "Hello $1!"
echo "Number of passed parameters: $#"
The result of running the script is shown below.
Variables in Bash are used to store data, such as strings and numbers. They can be explicitly defined by assigning a value or implicitly defined through automatic assignment during certain operations. To create a variable in Bash, you need to assign it a value using an equal sign (=
). For example:
company="Hostman"
Note that there should be no spaces between the variable name, the equal sign, and the value.
You can retrieve the value of a variable by specifying its name after the echo command and the $
sign. For example:
echo $company
It's also possible to assign a variable value through user input using the read command. For example, the following script prompts the user for their name and stores it in a variable:
#!/bin/bash
echo "What is your name?"
read name
echo "Hello, $name!"
The result of this script is shown below.
In Bash, there are several special variables that are automatically defined and filled by the system. For example, the $HOME
variable contains the path to the user's home directory, while $PWD
contains the path to the current working directory.
Additionally, there are environment variables that are defined by the system and can be used in scripts. For example, $PATH
contains a list of directories where Bash looks for executable files.
Variables can also be used to pass values between different commands and scripts. For example, to pass a variable’s value from one script to another, use the export
command:
export variable_name
Conditional operators allow you to execute a specific set of actions depending on whether a condition is true or false. In Bash scripts, conditions are written in brackets and passed to the if
command.
The syntax of the if
operator looks like this:
if [ condition ]
then
commands to execute if the condition is true
fi
Here, in the square brackets, you specify the condition that needs to be checked. If the condition is true, the commands between then
and fi
will be executed.
For example, let’s write a Linux script, evenodd.sh
, that checks whether the number entered by the user is even or odd:
#!/bin/bash
echo "Enter a number: "
read n
if (( $n % 2 == 0 ))
then
echo "The number $n is even"
else
echo "The number $n is odd"
fi
In this example, we use the %
operator, which calculates the remainder of division by 2. If the remainder is 0, the number is even; otherwise, it’s odd. The result of running the script is shown below.
Additionally, there are several comparison operators that can be used in conditional constructions:
-eq
– equal to;
-ne
– not equal to;
-gt
– greater than;
-lt
– less than;
-ge
– greater than or equal to;
-le
– less than or equal to.
For example, to check if the variable $a
is greater than the variable $b
, you can write the following:
if [ $a -gt $b ]
then
echo "$a is greater than $b"
fi
It is important to remember that you need to use spaces around the comparison operators in conditional constructions. If there are no spaces, Bash will treat this as one large string instead of a comparison operation.
In addition to if
, Bash scripts also use the case structure. This allows you to check a variable's value against several possible options. We will discuss this in the next chapter.
The case construction in Bash scripts allows you to simplify writing conditional operators for comparing variables with multiple possible values.
The syntax of the case construction is as follows:
case variable in
pattern1)
command1
;;
pattern2)
command2
;;
pattern3)
command3
;;
*)
default command
;;
esac
where variable
is the variable to check, pattern1
, pattern2
, pattern3
are the possible values to check, and command1
, command2
, command3
are the commands to execute depending on the value of the variable.
The *
symbol at the end of the list of values is used as a default handler if none of the values match the variable.
For example, let’s look at a script that checks the day of the week and performs the corresponding action:
#!/bin/bash
day=$(date +%u)
case $day in
1)
echo "Today is Monday"
;;
2)
echo "Today is Tuesday"
;;
3)
echo "Today is Wednesday"
;;
4)
echo "Today is Thursday"
;;
5)
echo "Today is Friday"
;;
6)
echo "Today is Saturday"
;;
7)
echo "Today is Sunday"
;;
*)
echo "Invalid day of the week"
;;
esac
In this example, we use the day
variable, which we define using the date +%u
command. In this case, %u
is used to obtain the numeric value of the day of the week, from 1 (Monday) to 7 (Sunday). Then we compare this variable with the days of the week using the case construction. If its value matches a certain day of the week, we display the corresponding message. If the value does not match any of the listed days, we display an error message.
The result of running the script is shown below.
Loops in Bash are used to perform repetitive actions. There are two types of loops: for
and while
.
The for
loop is used to execute commands for each element in a list.
The syntax of the for
loop is as follows:
for variable in list
do
commands
done
Here, the variable takes the value of an element from the list, and for each of them, the commands between do and done are executed.
Example:
#!/bin/bash
for i in {1..10}; do
echo "Number: $i"
done
In this example, i
takes values from 1 to 10, and for each of them, the echo "Number: $i"
command will be executed. The result of running this loop will look like this:
The while
loop is used to execute commands as long as the condition remains true. The syntax of the while
loop is as follows:
while [ condition ]
do
commands
done
Here, in square brackets, you specify the condition that is checked before each iteration of the loop. The commands between do
and done
will be executed as long as the condition is true.
Example:
#!/bin/bash
count=1
while [ $count -le 10 ]; do
echo "Count: $count"
count=$((count+1))
done
In this example, count
increases by 1 after each iteration of the loop. When the value of count
reaches 10, the loop terminates. The result of running this loop will look like this:
Functions in Bash are used to group commands into logically related blocks. Functions can be called from a script using their name.
The syntax of a function is as follows:
function_name () {
commands_and_expressions
}
The function name must start with a letter or an underscore and can contain only letters, numbers, and underscores. After the function name comes a list of arguments in parentheses. The commands and expressions to be executed when the function is called must be enclosed in curly braces.
Here’s an example of a function that outputs the current time and date:
#!/bin/bash
print_date () {
echo "Today's date: $(date)"
}
print_date # Function call
The result of running the script is shown below.
Functions can also accept arguments, which are passed as parameters inside the parentheses when calling the function. Here’s an example of a function that takes two arguments and outputs their sum:
#!/bin/bash
sum_numbers () {
result=$(( $1 + $2 ))
echo "The sum of $1 and $2 is $result"
}
sum_numbers 10 20 # Function call
In this example, $1
and $2
are variables that contain the values of the first and second arguments, respectively. sum_numbers 10 20
will call the sum_numbers
function with the arguments 10 and 20, and output the following result:
Functions can also return values using the return
keyword. Let’s rewrite the previous example using this new knowledge:
#!/bin/bash
sum_numbers () {
result=$(( $1 + $2 ))
return $result
}
sum_numbers 12 24 # Function call
echo "The sum of the numbers is $?" # Output
Here, the result is stored in the result
variable and returned from the function using the return
command.
The $?
variable contains the return code of the function, which in this case is the result of the sum calculation.
The result of running the script is shown below.
There is another way to handle the result of a function call without using return. Let’s slightly modify the previous script:
#!/bin/bash
sum_numbers () {
result=$(( $1 + $2 ))
echo $result
}
sum=$(sum_numbers 9 11)
echo "The sum of the numbers is $sum" # Output
Here, instead of using $?
and return
, we store the result of the function call in the sum
variable and then output its value. The result is shown below.
Bash scripts can be used to perform various operations with files and directories in Linux. For example, to check if a file exists, you can use the following command:
test -e filename
If the file exists, the command will return a value of 0; otherwise, it will return a non-zero value.
To work with directories in Bash scripts, you can use commands like cd
, mkdir
, rmdir
, ls
, and others.
Debugging Bash scripts can be a challenging task because problems can be caused by various factors, such as syntax errors, incorrect use of variables or functions, etc. For debugging Bash scripts, you can use tools like set -x
, set -v
, and set -e
.
The set -x
command allows you to display the commands before they are executed
The set -v
command displays the values of variables before they are used
The set -e
command stops the execution of the script in case of an error
Bash scripts are a powerful tool for automating tasks in UNIX-like operating systems. In this article, we covered the basic concepts and tools for writing Bash scripts, such as syntax, variables, conditional operators, loops, functions, and running scripts. We hope this guide helps you become a more productive and experienced Linux user.