Bash Scripting on Ubuntu: Automate Your Daily Tasks
Introduction
Ubuntu is a powerful operating system for software development, system administration, and everyday computing. One of its most useful features is the command-line interface, which allows users to interact with files, launch applications, install software, and manage system processes. Although you can perform these tasks individually by entering commands, repeating the same operations manually can become time-consuming. This is where Bash scripting becomes useful.
Bash is a command-line shell commonly used on Linux systems. It interprets commands and provides features for variables, loops, conditions, functions, and input handling. A Bash script is a text file containing commands that the shell executes in sequence. By combining commands into scripts, you can automate repetitive work and make common tasks easier to perform consistently.
For example, you can write a script that organizes files, creates project directories, checks whether a website is responding, processes log files, or creates backups of important documents. Instead of typing several commands every time you need to complete a task, you can run a single script.
Bash scripting is particularly useful for Ubuntu users because many Linux administration tools can be controlled through the terminal. Learning Bash also helps you understand how shell commands work together and prepares you for more advanced Linux administration and DevOps tasks.
In this tutorial, you will learn how to create and execute Bash scripts on Ubuntu, use variables and conditional statements, repeat commands with loops, define reusable functions, handle errors, and build practical automation projects. The examples are designed to help beginners progress from simple scripts to more structured automation.
1. What Is Bash Scripting?
Bash stands for Bourne Again SHell. It is a command-line shell that provides an environment for executing commands and scripting automated workflows.
When you open a terminal on Ubuntu, you may be using Bash or another configured shell. Bash accepts commands such as ls, cd, mkdir, and cp, which allow you to interact with the filesystem.
A Bash script places commands inside a file so that they can be executed together.
For example, imagine that you regularly create folders for new programming projects. You could enter each command manually, or you could create a script that prepares the folders automatically.
Bash scripts are useful for:
Creating and organizing directories.
Copying files and generating backups.
Processing text files and system logs.
Automating development workflows.
Checking system resources.
Running scheduled maintenance tasks.
Combining existing Linux utilities into repeatable workflows.
Bash is not a replacement for every programming language. It is particularly effective when coordinating shell commands and operating system utilities. For complex applications involving substantial data structures, sophisticated interfaces, or extensive business logic, Python and other languages may be more appropriate.
Understanding when to use Bash helps you choose the right tool for each automation problem.
2. Check Bash on Your Ubuntu System
Most standard Ubuntu Desktop installations include Bash. You can verify that the shell is available by running:
bash --version
The terminal should display version information.
You can also check which shell is configured for your current session:
echo "$SHELL"
This variable commonly contains a path such as /bin/bash, although the current shell and the configured login shell are not necessarily the same.
To check the path to the Bash executable, run:
command -v bash
If Bash is installed, this command prints its location.
For the following examples, create a dedicated directory for your scripts:
mkdir -p ~/bash-projects
cd ~/bash-projects
Keeping your scripts in a dedicated directory helps you organize your experiments and avoid accidentally modifying unrelated files.
3. Write Your First Bash Script
Your first script will display a welcome message.
Create a new file:
nano hello.sh
Enter the following code:
#!/usr/bin/env bash
echo "Hello, Ubuntu!"
echo "Welcome to Bash scripting."
echo "I am learning Linux automation."
Save the file by pressing Ctrl + O, confirming the filename, and pressing Ctrl + X.
The first line is called a shebang. It identifies the interpreter that should execute the script when it is launched as an executable file.
The echo command prints text to the terminal.
There are two common ways to execute this script.
Method One: Run the Script Through Bash
Use:
bash hello.sh
Bash reads the file and executes its commands.
This method works even if the script does not have executable permission, provided you have permission to read the file.
Method Two: Make the Script Executable
First, add executable permission:
chmod +x hello.sh
Then run:
./hello.sh
The chmod +x command changes the file permissions to allow execution, subject to the other permission and filesystem rules.
The ./ prefix tells the shell to look for the script in the current directory.
You should see the three welcome messages displayed in your terminal.
This simple exercise introduces the basic Bash workflow: create a file, write commands, save the script, and execute it.
4. Understand Variables in Bash
Variables allow you to store information that can be reused throughout a script.
For example:
#!/usr/bin/env bash
name="Alex"
language="Bash"
echo "Hello, $name!"
echo "You are learning $language scripting."
The script stores two values in variables and then inserts those values into the output.
Bash variable assignments must not contain spaces around the equals sign. For example, name="Alex" is valid, while name = "Alex" is interpreted differently and will not perform the intended assignment.
You can also obtain information from commands and save it in a variable.
#!/usr/bin/env bash
current_directory="$(pwd)"
current_date="$(date +%F)"
echo "Current directory: $current_directory"
echo "Current date: $current_date"
The $(...) syntax performs command substitution. Bash executes the command inside the parentheses and replaces the expression with its output.
In this example, pwd reports the current directory, while date +%F displays the date in a year-month-day format.
Variables make scripts more flexible because you can change a value in one place instead of editing several commands.
5. Accept User Input
Some scripts need information from the person running them. Bash provides the read command for this purpose.
Create a file called greeting.sh:
#!/usr/bin/env bash
read -r -p "Enter your name: " name
echo "Welcome, $name!"
echo "Your Ubuntu scripting journey starts here."
Run it with:
bash greeting.sh
The -p option displays a prompt, and -r prevents backslashes from being treated as escape characters during input reading.
When the user enters a name, the script stores it in the name variable and uses it in the output.
User input can make scripts more interactive. You can use the same approach to request a project name, a directory path, or a preferred action.
However, do not assume that user input is always valid. Scripts that accept filenames, paths, or commands should validate the input before using it.
For example, a script that deletes files should not immediately trust an arbitrary path entered by a user. It should check the path and clearly define what the script is allowed to remove.
6. Use Conditional Statements
Conditional statements allow Bash scripts to make decisions based on a condition.
For example, a script can check whether a file exists before attempting to read it.
#!/usr/bin/env bash
file="notes.txt"
if [[ -f "$file" ]]; then
echo "The file exists."
else
echo "The file does not exist."
fi
The [[ -f "$file" ]] condition checks whether the path refers to a regular file.
If the file exists, the first branch runs. Otherwise, the script displays the alternative message.
Bash supports several useful file tests:
-e checks whether a path exists.
-f checks whether a path is a regular file.
-d checks whether a path is a directory.
-r checks whether a path is readable.
-w checks whether a path is writable.
For example, you can check whether a project directory exists:
#!/usr/bin/env bash
directory="$HOME/bash-projects"
if [[ -d "$directory" ]]; then
echo "The project directory is ready."
else
echo "The project directory is missing."
fi
Notice that the path is surrounded by double quotation marks when it is used as a variable. Quoting variable expansions helps prevent problems when paths contain spaces or wildcard characters.
Conditions are essential for automation because they let scripts respond to different situations instead of blindly executing the same commands every time.
7. Repeat Tasks with Loops
Loops allow you to execute commands multiple times.
A for loop is useful when you want to process a list of values.
For example:
#!/usr/bin/env bash
for language in Python JavaScript C++ Rust
do
echo "Learning $language"
done
Bash assigns each item to the language variable and runs the commands inside the loop.
Loops can also create multiple directories:
#!/usr/bin/env bash
for directory in projects documents backups scripts
do
mkdir -p "$HOME/$directory"
done
echo "Directories created."
The mkdir -p command creates missing directories without reporting an error merely because a directory already exists.
Another useful loop is the while loop, which repeats commands while a condition remains true.
#!/usr/bin/env bash
count=1
while (( count <= 5 ))
do
echo "Iteration $count"
((count += 1))
done
This script prints five iterations.
Loops are particularly helpful when processing lists of files, running repeated checks, or applying the same operation to several project directories.
Be careful when writing while loops. A loop that never changes its condition may run indefinitely. Always ensure that the script has a clear way to reach its stopping condition.
8. Create Reusable Functions
Functions group related commands into reusable blocks. They help you avoid repeating the same instructions throughout a script.
Consider this example:
#!/usr/bin/env bash
show_message() {
echo "--------------------------"
echo "$1"
echo "--------------------------"
}
show_message "Welcome to Ubuntu"
show_message "Bash scripting is useful"
The show_message function prints a message between separator lines.
The expression $1 represents the first positional argument passed to the function.
You can use additional positional parameters such as $2 and $3 when a function needs more than one argument.
For example:
#!/usr/bin/env bash
create_project() {
local project_name="$1"
if [[ -z "$project_name" ]]; then
echo "Error: project name is required." >&2
return 1
fi
mkdir -p "$HOME/bash-projects/$project_name"
echo "Project directory created."
}
create_project "website-demo"
The local keyword limits the variable's scope to the function. The -z test checks whether the string is empty, and return 1 indicates that the function did not complete successfully.
Functions are useful when a script has several related tasks, such as validating inputs, preparing directories, checking files, and reporting results.
As scripts become larger, dividing them into functions makes the logic easier to understand and maintain.
9. Understand Exit Codes and Error Handling
When a command finishes, it usually returns an exit status. An exit status of 0 generally indicates success, while a nonzero status indicates a failure or another condition that the program uses to report its result.
Bash stores the previous command's exit status in $?.
For example:
mkdir -p "$HOME/bash-projects/demo"
if [[ $? -eq 0 ]]; then
echo "Directory operation succeeded."
else
echo "Directory operation failed."
fi
For a simple command, it is often clearer to place the command directly inside an if statement:
if mkdir -p "$HOME/bash-projects/demo"; then
echo "Directory operation succeeded."
else
echo "Directory operation failed."
fi
This form checks the command's result directly and avoids accidentally checking the exit status of an intervening command.
For more structured scripts, you may encounter these settings:
set -e
set -u
set -o pipefail
Together, they are commonly used as part of a strict-mode approach. They can help expose certain failures, unset variable references, and unsuccessful commands inside pipelines.
However, they are not a substitute for understanding error handling. Bash has exceptions to these rules, including situations involving conditionals, functions, and pipelines. Scripts should still check important operations explicitly.
For example, when creating a backup, it is better to verify that the archive was created successfully than to print a success message unconditionally.
Reliable scripts report failures clearly and avoid continuing when a critical operation has not completed as expected.
10. Automate File Backups on Ubuntu
Backing up important files is a practical way to learn Bash scripting. A script can create a dated archive of a selected directory, helping you keep separate backup versions.
The following example uses tar to archive a directory and checks whether the operation succeeds.
Create a file called backup.sh:
#!/usr/bin/env bash
set -u
source_dir="$HOME/Documents"
backup_dir="$HOME/backups"
if [[ ! -d "$source_dir" ]]; then
echo "Error: source directory does not exist." >&2
exit 1
fi
if ! mkdir -p "$backup_dir"; then
echo "Error: could not create backup directory." >&2
exit 1
fi
timestamp="$(date +%Y%m%d_%H%M%S)"
archive="$backup_dir/documents_$timestamp.tar.gz"
if tar -czf "$archive" -C "$source_dir" .; then
echo "Backup created successfully:"
echo "$archive"
else
echo "Error: backup operation failed." >&2
exit 1
fi
Save the script and run:
bash backup.sh
The script checks whether the source directory exists, creates the backup destination if necessary, and generates an archive with a timestamp in its filename.
The tar options have the following meanings:
-c creates a new archive.
-z compresses the archive using gzip.
-f specifies the output filename.
-C changes the directory used as the starting point for archiving.
The command archives the contents of the Documents directory rather than placing the full absolute path into the archive.
Before relying on any backup script, test it with nonessential files. Confirm that the resulting archive contains the expected information and that you can extract it successfully. Also consider what happens if the destination becomes full or the source files change during the backup.
A backup is only useful if the files can be recovered. Keep important backups on a separate device or trusted remote storage rather than relying exclusively on a folder on the same disk.
11. Build a System Information Script
Another useful beginner project is a script that displays basic information about your Ubuntu computer.
Create a file named system_info.sh:
#!/usr/bin/env bash
echo "===== Ubuntu System Information ====="
echo
echo "Current user:"
whoami
echo
echo "Hostname:"
hostname
echo
echo "Current directory:"
pwd
echo
echo "Disk usage:"
df -h "$HOME"
echo
echo "Memory information:"
free -h
echo
echo "System uptime:"
uptime
Run it using:
bash system_info.sh
The script combines several Linux utilities to display information about the current user, hostname, disk usage, memory, and system uptime.
The df -h command reports filesystem space in human-readable units. The free -h command summarizes memory usage, and uptime reports how long the system has been running along with load information.
This example demonstrates one of Bash's greatest strengths: it can coordinate existing command-line tools without requiring you to implement their functionality from scratch.
You can expand the script to display the Ubuntu release, available disk space, or the current network configuration. Keep in mind that some commands and output formats may vary across Linux distributions and software versions.
12. Check Whether a Website Is Responding
Bash can also automate basic network checks. For example, you can use curl to request a webpage and inspect the HTTP response status.
First, ensure that curl is installed:
sudo apt update
sudo apt install curl
Create a file named website_check.sh:
#!/usr/bin/env bash
url="https://example.com"
if status_code="$(
curl --silent \
--output /dev/null \
--write-out '%{http_code}' \
--connect-timeout 5 \
--max-time 15 \
"$url"
)"; then
case "$status_code" in
2??|3??)
echo "The server returned HTTP $status_code."
;;
*)
echo "The server returned HTTP $status_code." >&2
exit 1
;;
esac
else
echo "The request failed or timed out." >&2
exit 1
fi
Run the script:
bash website_check.sh
The example requests https://example.com and displays the HTTP status code returned by the server. Successful responses and redirects are reported separately from other HTTP statuses.
The --connect-timeout option limits the time spent establishing a connection, while --max-time limits the overall request duration.
An HTTP response does not necessarily mean that every part of a website is functioning correctly. A server may respond while a particular application feature is broken. For production monitoring, use checks that match the service's actual requirements.
This example is useful for learning how Bash can coordinate network utilities and respond to their results.
13. Schedule Bash Scripts with Cron
Sometimes you want a script to run automatically at a specific time without manually launching it.
On Ubuntu, the cron scheduling system can run commands according to a defined schedule when the relevant service is available and operating normally.
For example, you may want to run a backup script every day.
First, identify the script's absolute path:
realpath ~/bash-projects/backup.sh
Ensure the script works correctly when run manually. If it uses a relative path or depends on interactive environment variables, adjust it so that it behaves predictably when scheduled.
Open your user crontab:
crontab -e
Add an entry like this, replacing the example path with the actual absolute path to your script:
0 2 * * * /home/youruser/bash-projects/backup.sh >> /home/youruser/backup.log 2>&1
This schedule requests execution at 02:00 every day, according to the system's local time configuration.
The five scheduling fields represent minute, hour, day of the month, month, and day of the week.
The >> operator appends output to the log file, while 2>&1 redirects standard error to the same destination as standard output.
Replace /home/youruser with your actual home directory. Do not copy the placeholder literally.
Scheduled jobs often run with a more limited environment than an interactive terminal. Use absolute paths for scripts and files, ensure the necessary commands are available, and record errors so you can investigate failures.
Also consider whether the computer will be powered on at the scheduled time. Cron is not, by itself, a guarantee that a task will run if the machine is shut down or suspended.
14. Follow Bash Scripting Best Practices
Writing a script that works once is different from writing one that is safe and reliable over time.
Use descriptive filenames such as backup_documents.sh rather than generic names that do not explain the script's purpose.
Quote variable expansions when using paths or other values:
cp -- "$source_file" "$destination_file"
Quoting protects spaces and many special characters from being interpreted as word separators or shell patterns. The -- indicates that the following arguments are not options, which is helpful when filenames begin with a hyphen.
Avoid placing destructive commands in scripts without checks. A script that removes files should validate its target directory and should never rely on an empty or incorrectly constructed variable.
Do not use sudo automatically for every script. Administrative privileges should be used only when genuinely required.
Keep scripts focused on a clear purpose. If a script grows too large, divide its work into functions or separate components.
Use comments to explain important decisions rather than restating every obvious command.
For scripts that need reliable failure detection, check the exit status of critical commands and print useful error messages.
Finally, test scripts using sample files and temporary directories before running them against important data. Testing is particularly important for scripts that move, overwrite, or delete files.
15. Common Bash Scripting Mistakes
Beginners often encounter similar problems while learning shell scripting.
Forgetting to Add Executable Permission
If you run a script directly and receive a permission error, check the file's permissions.
Use:
chmod +x script.sh
Then execute it with:
./script.sh
Alternatively, run it through Bash:
bash script.sh
Using Spaces in Variable Assignments
This is incorrect for a normal assignment:
name = "Alex"
Use:
name="Alex"
Bash interprets spaces as separators between command arguments, so spaces around the assignment operator change its meaning.
Forgetting to Quote File Paths
A path such as My Documents/report.txt contains a space. Without appropriate quoting, the shell may interpret it as separate arguments.
Use:
file="$HOME/My Documents/report.txt"
cat -- "$file"
Quoting variable expansions is a valuable habit, particularly in scripts that process filenames.
Assuming Every Command Succeeded
A script may continue after a command fails, potentially producing incomplete output or an incorrect success message.
Check the result of important operations and stop or recover when necessary.
Testing Only One Scenario
A script that works with one input may fail when a directory is missing, a filename contains spaces, or a network connection is unavailable.
Test expected situations and failure conditions before relying on automation.
16. Practical Exercises to Improve Your Bash Skills
The best way to learn Bash is to practice creating your own scripts.
Try these exercises:
Create a script that asks for a name and displays a personalized greeting.
Write a script that creates a project directory with subdirectories for source code, documentation, and tests.
Build a script that lists all regular files in a specified directory.
Create a script that counts the number of lines in a text file.
Write a backup script that checks the source directory and reports whether the archive was created successfully.
Build a system information script that displays disk usage and memory statistics.
Create a website-checking script that records its result in a log file.
Schedule a harmless script to run at a regular interval and inspect its log output.
Begin with the simplest exercises and gradually introduce functions, conditions, loops, and error handling.
For each exercise, ask yourself what could go wrong and how the script should respond. This habit will help you develop more reliable automation rather than merely memorizing commands.
Conclusion
Bash scripting is a valuable skill for Ubuntu users who want to automate repetitive tasks and work more efficiently with Linux. By combining commands into reusable scripts, you can create directories, manage files, generate backups, inspect system information, and perform basic network checks with less manual effort.
The fundamentals are straightforward: learn how to create and execute scripts, use variables, accept input, make decisions with conditions, repeat work with loops, and organize commands into functions. As your scripts become more complex, pay attention to exit statuses, error handling, file permissions, and input validation.
Bash is especially effective when you need to coordinate existing Linux utilities. It is widely useful in system administration, development workflows, and routine maintenance. However, choose another language when a task requires capabilities that are difficult to maintain in a shell script.
Start with a small script that solves a real problem on your computer. Test it carefully, improve its error handling, and add features gradually. With regular practice, you will become more comfortable with the Ubuntu terminal and learn how to turn repetitive commands into reliable automation.
Frequently Asked Questions
Is Bash scripting difficult for beginners?
Bash scripting is accessible to beginners who already know a few terminal commands. You can start with simple commands and gradually learn variables, conditions, loops, and functions.
Is Bash installed by default on Ubuntu?
Bash is included in standard Ubuntu installations. You can verify its availability by running bash --version in the terminal.
What is the difference between a Bash command and a Bash script?
A Bash command is an instruction entered into the shell. A Bash script is a file containing one or more commands that can be executed together.
Can Bash scripts automate backups?
Yes. Bash scripts can coordinate tools such as tar, cp, and other utilities to create backups. Always verify that backups can be restored and store important copies separately from the original data.
Can Bash replace Python?
Not for every task. Bash is particularly useful for coordinating shell commands and automating operating system workflows. Python is generally more convenient for complex data processing, larger applications, and programs that require more extensive logic.
How can I run a Bash script automatically?
You can schedule scripts using cron or other scheduling tools available on Ubuntu. Configure the schedule carefully, use absolute paths, and check logs to confirm that the task is working as expected.
Comments
Post a Comment