Lesson 14 of 29 ↓
- 1.Rhel 9 Administration Guide
- 2.Ubuntu Boot Process Guide
- 3.Linux Basic Commands Guide
- 4.Comprehensive Unix Shells Guide
- 5.Mastering Vim Deep & Practical Guide
- 6.Magic Numbers in Linux Deep Systems Guide
- 7.Wildcards & Globbing in Linux Deep Cli Guide
- 8.Linux Users & Groups Deep Administration Guide
- 9.Journaling in Linux Filesystems Deep Systems Guide
- 10.Getopt & Getoptlong Deep System-level Option Parsing Guide
- 11.Su Command in Linux Complete Guide with Environment Variables
- 12.Linux File Permissions and Ownership Complete Practical Guide
- 13.Ubuntu Package Management Apt Complete Guide
- 14.Bash Scripting Basics
- 15.Linux File System Essentials
- 16.Process and Thread Management
- 17.Session 10 : Introduction to Networking & the Application Layer
- 18.Linux Networking Cli & Introduction to Yocto for Machine Routing
- 19.Comprehensive Guide to Ssh (secure Shell)
- 20.Logical Volume Management (lvm) Guide
- 21.C Build Process & Libraries Guide
- 22.Archiving and Compression in Linux
- 23.Linux Package Managers: a Detailed Guide
- 24.Misra-c Guidelines Detailed Cheat Sheet
- 25.Mqtt Server Setup (pc as Server)
- 26.Detailed Explanation of Tty and Pts in Linux
- 27.Vim Cheat Sheet
- 28.Difference Between apt and apt-get
- 29.Difference Between apt Upgrade and apt Full-upgrade
16 min read
Bash Scripting Basics
A guide explaining the fundamental concepts of Bash scripting.
Environment Setup: Jupyter Notebook
To run Bash commands interactively in a notebook environment, you can install Jupyter and the bash_kernel.
-
Install pip (Example for Fedora/RHEL systems):
bash sudo dnf install python3-pip -
Install the bash_kernel:
bash pip install bash_kernel -
Install the kernel into Jupyter:
bash python3 -m bash_kernel.install
Shebang
Before anything else, you should start your script with a Shebang. This line tells the system which interpreter to use to execute the file.
For example, to use Bash:
#!/bin/bashDefining Variables
Local Variable A variable that is only available within the script where it is defined.
VAR="Value"Global Variable To make a variable available to any sub-shells or child processes, you must export it.
export VAR="Value"Using declare You can use the declare command to explicitly state the type of variable or set attributes.
# Integer value: Forces the variable to be treated as a number
declare -i num=16
# num="text" # This would be treated as 0 because it expects an integer
# Read-only (constant) value: Cannot be changed later
declare -r pi=3.14
# pi=3.14159 # This would cause an error
# Indexed Array (Standard 0, 1, 2... index)
declare -a names=(ahmed sami)
names[2]=mahmoud # Adding an element
# Associative Array (Key-Value pairs like Dictionaries/HashMaps) - Requires Bash 4.0+
declare -A user_ages
user_ages[Ali]=25
user_ages[Sara]=30
echo "Ali is ${user_ages[Ali]} years old"
# Attribute: Lowercase (Automatically converts assigned value to lowercase)
declare -l lower_text
lower_text="HELLO WORLD" # Value becomes "hello world"
# Attribute: Uppercase (Automatically converts assigned value to uppercase)
declare -u upper_text
upper_text="hello world" # Value becomes "HELLO WORLD"
# Inspecting: Prints the definition/attributes of a variable
declare -p names # Useful for debugging to see array content
Running a Bash Script
There are three common ways to execute a Bash script:
-
Make the file executable This method requires the script to have a shebang.
bash # 1. Add execute permissions to the file chmod +x your_script_name.sh # 2. Run the script ./your_script_name.sh -
Using the
bashcommand This runs the script in a new sub-shell. Environment variables changed by the script will not affect your current shell.bash bash your_script_name.sh -
Using the
sourcecommand This runs the script in the current shell. Any environment variables changed by the script will affect your current shell.bash source your_script_name.sh
User Input
You can get input from the user with the read command.
Reading Input The -p flag is used to display a prompt message without a newline. The -s flag makes the input silent (for passwords), and -r prevents backslash interpretation.
read -rp "Please enter your name: " user_namePrinting Output Use the echo command to print the variable's value. You must prefix the variable name with a $.
# Print just the variable
echo $user_name
# or print it within a string
echo "Hello, $user_name!"Command-line Arguments
You can pass arguments to your script when you run it from the command line.
For example:
./your_script.sh argument1 "argument 2"Inside the script, you can access these arguments using special variables:
-
$#: Stores the total number of arguments.bash # This command prints the number of arguments echo "You provided $# arguments." -
$0: The name of the script itself. -
$1,$2, etc.: The arguments themselves.$1is the first argument,$2is the second, and so on.bash # This command prints the first argument echo "The first argument is: $1" -
$*: Expands to all the arguments as a single string (arguments are separated by the first character of the IFS special variable, typically a space). -
$@: Expands to all the arguments as separate words. This is useful for iterating over all the arguments.bash # This command loops through all the arguments and prints them one by one for arg in "$@" do echo "Argument: $arg" done
Quoting
The difference between single and double quotes is very important in Bash.
-
Single Quotes (
') Everything inside single quotes is treated as a literal string. No variable expansion or command substitution will occur.bash VAR="World" echo 'Hello, $VAR' # Output: Hello, $VAR -
Double Quotes (
") Double quotes allow for variable expansion and command substitution. Special characters are interpreted.bash VAR="World" echo "Hello, $VAR" # Output: Hello, WorldYou can also run commands inside double quotes using
$(...):bash # This will print "test " followed by the output of the ls command echo "test $(ls)"To print a special character literally inside double quotes, you can escape it with a backslash (
\):bash # This will print "hello $(ls)" literally echo "hello \$(ls)"
Word Splitting
When a variable contains spaces and is used without quotes, Bash performs "word splitting" and treats each word as a separate argument.
VARA=Hello
VARB="Hello There"
# This will create one directory named "Hello"
mkdir $VARA
# This will create TWO directories: one named "Hello" and one named "There"
mkdir $VARB
# To treat the variable's value as a single argument, enclose it in double quotes:
mkdir "$VARB" # This creates one directory named "Hello There"Arithmetic Operations
To perform math in Bash, use the $((...)) arithmetic expansion syntax.
x=10
y=5
# Addition
echo $((x + y)) # Output: 15
# Subtraction
echo $((x - y)) # Output: 5
# Multiplication
echo $((x * y)) # Output: 50
# Division
echo $((x / y)) # Output: 2
# Power / Exponentiation
echo $((y ** 2)) # Output: 25
# Incrementing a variable
((x++))
echo $x # Output: 11The following operators are available inside ((...)): +, -, *, /, % (modulo), ** (exponentiation), ++, --, +=, -=, == (equality), != (not equal), && (logical AND), || (logical OR).
Other Methods for Arithmetic You can also use expr for basic math or bc (Basic Calculator) for more advanced operations (like floating-point math or powers).
#!/bin/bash
# ARITHMETIC OPERATIONS
num=4
echo $((num*5)) # using echo $(())
expr $num + 6 # using expr
echo $num ^ 4 | bc # using bc
Conditional Statements
There are two main ways to handle conditions in Bash: if statements and case statements.
if Statements
The if statement allows you to execute code based on a condition.
Syntax:
-
Multi-line (Recommended):
bash if [[ condition ]] then # statement to execute if condition is true # You can use 'exit' to terminate the script. # exit 0 --> indicates success elif [[ another_condition ]] then # statement to execute if another_condition is true # exit [1-255] --> indicates an error else # statement to execute if no conditions are true fi -
Single-line:
bash if [[ condition ]]; then echo "True"; else echo "False"; fi
Understanding Test Expressions: [ ] vs [[ ]]
Bash provides two primary ways to evaluate test expressions: [ ] (single brackets) and [[ ]] (double brackets). Understanding the differences is crucial for writing effective conditional statements.
-
Single Brackets
[ ]-
Usage: Traditional
testcommand. -
Compatibility: More portable across different shells (Bourne shell compatible).
-
Limitations: Less powerful; requires careful quoting of variables to prevent word splitting and globbing issues.
-
-
Double Brackets
[[ ]]-
Usage: An enhanced test command specific to Bash.
-
Features: Prevents word splitting and globbing, supports additional operators like pattern matching (
=~), and allows logical operators like&&and||inside.
-
Logical Operators & Compound Commands
You can use logical operators to combine commands or test results.
-
&&(AND): The second command runs only if the first one succeeds (returns 0). -
||(OR): The second command runs only if the first one fails (returns non-zero). -
!(NOT): Inverts the exit status of a command.
Examples:
# The 'true' command always returns 0 (success)
true; echo $? # Output: 0
# The 'false' command always returns 1 (failure)
false; echo $? # Output: 1
# Logical AND: Echo runs because 'true' succeeds
true && echo "True"
# Logical OR: Echo runs because 'false' fails
false || echo "False"
# Using [[ ]] with logical operators
[[ 1 -le 2 ]]; echo $? # Returns 0 (True)
[[ 3 == 3 ]]; echo $? # Returns 0 (True)
[[ 3 != 3 ]]; echo $? # Returns 1 (False)
The test Command
The test command is functionally equivalent to [ ]. It checks file types and compares values.
# Check if a file exists
test -f /etc/hosts; echo $?
# Check if a file is readable
test -r /etc/shadow; echo $?
# Compare integers
test 1 -le 5; echo $?
Common Comparison Operators
Bash offers a variety of operators to compare integers, strings, and file attributes.
- Numeric Comparison Operators (for integers)
| Operator | Description |
|---|---|
-eq |
Equal to |
-ne |
Not equal to |
-lt |
Less than |
-le |
Less than or equal to |
-gt |
Greater than |
-ge |
Greater than or equal to |
Example: Numeric Comparisons
#!/bin/bash
a=5
b=10
# Simple comparison using single brackets
if [ "$a" -lt "$b" ]; then
echo "$a is less than $b."
fi
# Compound comparison using double brackets
if [[ "$a" -gt 3 && "$b" -le 15 ]]; then
echo "$a is greater than 3 and $b is less than or equal to 15."
fi- String Comparison Operators
| Operator | Description | Works In |
|---|---|---|
= |
Equal to | [ ] and [[ ]] |
== |
Equal to (preferred in [[ ]]) |
[ ] and [[ ]] |
!= |
Not equal to | [ ] and [[ ]] |
< |
Less than (ASCII sort order) | [[ ]] only |
> |
Greater than (ASCII sort order) | [[ ]] only |
Example: String Comparisons
#!/bin/bash
str1="apple"
str2="banana"
if [ "$str1" = "banana" ]; then
echo "Strings are equal."
else
echo "Strings are not equal."
fi
if [[ "$str1" < "$str2" ]]; then
echo "$str1 comes before $str2 alphabetically."
fi- File & Directory Operators
| Operator | Description |
|---|---|
-e |
True if the file or directory exists. |
-f |
True if it exists and is a regular file. |
-d |
True if it exists and is a directory. |
-s |
True if the file exists and is not empty. |
-r |
True if the file is readable. |
-w |
True if the file is writable. |
-x |
True if the file is executable. |
Example: File Attribute Checks
#!/bin/bash
FILE="/home/ali/script.sh"
if [ -f "$FILE" ]; then
echo "$FILE is a regular file."
fi
if [[ -x "$FILE" ]]; then
echo "$FILE is executable."
fiExample: User Login
#!/bin/bash
read -rp "please enter your username: " username
read -s -p "please enter your password: " password
echo
if [[ "$username" == "admin" && "$password" == "admin" ]]; then
echo "successful login"
exit 0
else
echo "username or password is incorrect"
exit 1
fiExample: Even or Odd Number
#!/bin/bash
# Ask the user for a number
read -p "Enter a number: " number
# Check if the number is even or odd
if (( number % 2 == 0 )); then
echo "The number is even."
else
echo "The number is odd."
fiChecking the Exit Status ($?)
Every command in Linux returns an exit status (also called a return code). This is a number between 0 and 255.
-
0means the command was successful. -
Any number from
1to255means the command failed.
The special variable $? always holds the exit status of the last executed command. You can use this to check if a command or a condition was successful.
Example:
if [[ -f file.txt ]]; then
echo "The file exists on your system."
mkdir -p hello_there # This will have an exit status of 0 if it runs well
else
echo "File not found."
exit 2 # Explicitly exit with an error code
fi
# Now, check the exit status of the last command (either mkdir or the script itself if it exited)
if [[ $? -eq 0 ]]; then
echo "The program finished successfully."
else
echo "The program finished with an error."
fiNote
The
[command is an actual program (or shell builtin). You can learn more about its options by runningman [in your terminal.
case Statements
The case statement is a cleaner way to write multiple if/elif/else conditions when you are checking a single variable against a series of different values (patterns).
Syntax:
case $VARIABLE in
pattern1)
# commands to execute if VARIABLE matches pattern1
;;
pattern2|pattern3)
# commands to execute if VARIABLE matches pattern2 OR pattern3
;;
*)
# default commands to execute if no other pattern matches
;;
esacKey Points:
-
The statement starts with
caseand ends withesac(case spelled backward). -
Each block of conditions ends with
;;. -
You can use the pipe
|to represent an "OR" condition for multiple patterns. -
The
*)is a wildcard pattern that acts as a default case, similar toelse.
Example 1: Service Control
#!/bin/bash
read -p "Enter 'start', 'stop', or 'status': " command
case $command in
start)
echo "Starting the service..."
;;
stop)
echo "Stopping the service."
;;
status|check)
echo "Checking the service status."
;;
*)
echo "Invalid command. Please use 'start', 'stop', or 'status'."
;;
esacExample 2: Simple Calculator
#!/bin/bash
read -p "Enter first number: " num1
read -p "Enter second number: " num2
read -p "Enter operator (+, -, *, /): " operator
case $operator in
+)
echo "$num1 + $num2 = $((num1 + num2))"
;;
-)
echo "$num1 - $num2 = $((num1 - num2))"
;;
\*)
echo "$num1 * $num2 = $((num1 * num2))"
;;
/)
if [ "$num2" -ne 0 ]; then
echo "$num1 / $num2 = $((num1 / num2))"
else
echo "Error: Division by zero"
fi
;;
*)
echo "Invalid operator!"
;;
esacLoops
Loops allow you to execute a block of code multiple times. Bash supports for, while, and until loops.
for Loops
A for loop is used to iterate over a list of items and perform a given set of commands.
Syntax 1: Iterating over a list
for VARIABLE in item1 item2 item3 ...
do
# commands to execute for each item
doneExample:
#!/bin/bash
# Loop through a list of fruits
for fruit in apple banana cherry
do
echo "I like $fruit"
doneSyntax 2: C-style for loop
for (( INITIALIZATION; CONDITION; INCREMENT ))
do
# commands to execute
doneExample:
#!/bin/bash
# Print numbers from 1 to 5
for (( i=1; i<=5; i++ ))
do
echo "Count: $i"
donewhile Loops
A while loop executes a block of code as long as a given condition is true.
Syntax:
while [[ condition ]]
do
# commands to execute
doneExample:
#!/bin/bash
counter=1
while [[ $counter -le 5 ]]
do
echo "Counter is at $counter"
((counter++))
doneuntil Loops
An until loop is the opposite of a while loop. It executes a block of code as long as a given condition is false.
Syntax:
until [[ condition ]]
do
# commands to execute
doneExample:
#!/bin/bash
counter=1
until [[ $counter -gt 5 ]]
do
echo "Counter is at $counter"
((counter++))
doneLoop Control (break and continue)
You can control the flow of your loops with the break and continue statements.
-
break: Exits the current loop immediately. -
continue: Skips the current iteration of the loop and moves to the next one.
Example:
#!/bin/bash
# Print odd numbers from 1 to 10
for (( i=1; i<=10; i++ ))
do
# If the number is even, skip to the next iteration
if (( i % 2 == 0 )); then
continue
fi
echo $i
doneFunctions
Functions allow you to group a set of commands together, give them a name, and then run them from other places in your script. This helps make your scripts more organized, reusable, and easier to read.
Defining a Function
There are two common ways to define a function.
Syntax 1:
function function_name {
# commands
}Syntax 2 (more common):
function_name() {
# commands
}Note: You must define a function before you call it in your script.
Calling a Function
To run the code inside a function, you simply call it by its name.
function_namePassing Arguments to Functions
You can pass arguments to functions just like you do with scripts. Inside the function, you can access these arguments using the positional parameters $1, $2, $3, etc. $0 will still refer to the script name.
Returning Values from Functions
Bash functions don't return values in the way many other programming languages do. They have two main ways of providing a result:
-
Return Status: Using the
returncommand, a function can return a numeric exit status (a number from 0 to 255) to the caller. This is useful for indicating success (return 0) or failure (any other number). The calling script can check this status using the$?variable. -
Standard Output: The most common method is to have the function
echoorprintfa result. The calling part of the script can then capture this output using command substitution$(...).
Example 1: Simple Greeting
This function prints a simple message.
#!/bin/bash
# Define the function
greet() {
echo "Hello, World!"
}
# Call the function
greetExample 2: Function with Arguments
This function takes a name as an argument and prints a personalized greeting.
#!/bin/bash
greet_user() {
# $1 refers to the first argument passed to the function
echo "Hello, $1!"
}
# Call the function with an argument
greet_user "Alice"
greet_user "Bob"Example 3: Function Returning a Value via Output
This function takes two numbers, adds them, and "returns" the result by printing it. The main script captures this result into a variable.
#!/bin/bash
add() {
local num1=$1
local num2=$2
local sum=$((num1 + num2))
echo $sum
}
# Call the function and capture its output into a variable
result=$(add 5 10)
echo "The sum is: $result"Example 4: Function Returning a Status
This function checks if a file exists and returns a status code. The main script checks this status to see if the function succeeded.
#!/bin/bash
# This function checks if a file exists
check_file() {
if [[ -f "$1" ]]; then
return 0 # Success
else
return 1 # Failure
fi
}
# Call the function
check_file "/etc/hosts"
# Check the return status of the function
if [[ $? -eq 0 ]]; then
echo "File found successfully."
else
echo "File not found."
fi
Comments
Loading the discussion…