Bash Programming
This guide covers the core concepts of Bash scripting, ranging from basic syntax to control structures, functions, and error handling.
1. Introduction to Bash
Bash (Bourne Again SHell) is a command-line interpreter and scripting language widely used in Unix-like operating systems. A Bash script is a plain text file containing a sequence of commands.
Creating and Running Your First Script
1. Create a file named myscript.sh.
2. Add the Shebang: The very first line of a Bash script must specify the path to the interpreter.
#!/bin/bash
echo "Hello, World!"
3. Make the script executable: By default, new files do not have execution permissions. Use chmod to grant permissions:
chmod +x myscript.sh
4. Execute the script:
./myscript.sh
2. Basic Syntax and Variables
Comments
Comments start with a # symbol and are ignored by the shell.
# This is a single-line comment
echo "This will run" # This is an inline comment
Variables
Variables in Bash do not require type declaration.
- Rules:
- No spaces around the
=sign during assignment. - Variable names are case-sensitive and typically written in uppercase by convention, though lowercase is also acceptable.
- To access a variable, prefix its name with
$.
# Correct assignment
name="Alice"
age=30
# Accessing variables
echo "My name is $name and I am $age years old."
Quoting Rules
How you quote variables determines how Bash processes them:
- Double Quotes (
"): Allows variable expansion and escape characters. - Single Quotes (
'): Treats all characters literally. No expansion occurs. - Backticks (`
`) or$()`: Used for command substitution (running a command and saving its output).
greeting="Hello"
echo "$greeting World" # Outputs: Hello World
echo '$greeting World' # Outputs: $greeting World
# Command substitution
current_dir=$(pwd)
echo "You are currently in: $current_dir"
3. Special Variables and Positional Parameters
Bash uses special variables to handle arguments passed to a script from the command line.
| Variable | Description |
|---|---|
$0 | The name of the script itself |
$1 to $9 | The first nine arguments passed to the script |
${10} | Tenth and subsequent arguments (require curly braces) |
$# | The number of arguments passed to the script |
$@ | All arguments passed to the script (individually quoted) |
$* | All arguments passed to the script (joined as a single string) |
$? | The exit status of the last executed command (0 means success) |
$$ | The process ID (PID) of the current shell |
Example Script (arguments.sh):
#!/bin/bash
echo "Script name: $0"
echo "First argument: $1"
echo "Second argument: $2"
echo "Total arguments: $#"
echo "All arguments: $@"
Execution:
./arguments.sh Apple Banana
Output:
Script name: ./arguments.sh
First argument: Apple
Second argument: Banana
Total arguments: 2
All arguments: Apple Banana
4. Input and Output
Reading User Input
The read command pauses execution to accept input from the standard input.
#!/bin/bash
# -p flag allows you to specify a prompt string
read -p "Enter your username: " username
echo "Welcome, $username!"
Prompting for Sensitive Information
Use the -s flag to hide the input (useful for passwords).
read -s -p "Enter password: " password
echo -e "\nPassword saved securely."
5. Conditional Statements
Bash uses if statements to make decisions. The test conditions are enclosed in brackets. It is recommended to use double brackets [[ ... ]] in modern Bash, as they are safer and offer more features than single brackets [ ... ].
Basic If-Else Syntax
#!/bin/bash
read -p "Enter a number: " num
if [[ $num -gt 10 ]]; then
echo "The number is greater than 10."
elif [[ $num -eq 10 ]]; then
echo "The number is exactly 10."
else
echo "The number is less than 10."
fi
Comparison Operators
Integer Comparisons:
-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
String Comparisons:
==: Equal to!=: Not equal to-z: String is empty-n: String is not empty
File Checks:
-e file: File or directory exists-f file: File exists and is a regular file-d file: Directory exists-r file: File has read permission-w file: File has write permission-x file: File has execute permission
Example File Check:
file_path="config.txt"
if [[ -f "$file_path" ]]; then
echo "$file_path exists and is a regular file."
else
echo "$file_path does not exist."
fi
6. Loops (For, While, Until)
For Loops
For loops iterate over a sequence or a list of items.
List Iteration:
for fruit in apple banana cherry; do
echo "Fruit: $fruit"
done
Range Iteration:
# Prints 1 to 5
for i in {1..5}; do
echo "Number: $i"
done
C-Style For Loop:
for ((i=0; i<3; i++)); do
echo "Counter: $i"
done
While Loops
A while loop runs as long as the specified condition evaluates to true.
counter=1
while [[ $counter -le 3 ]]; do
echo "Count is $counter"
((counter++))
done
Until Loops
An until loop runs as long as the specified condition evaluates to false (it stops once the condition becomes true).
counter=1
until [[ $counter -gt 3 ]]; do
echo "Count is $counter"
((counter++))
done
7. Functions
Functions allow you to group blocks of code for reuse.
Syntax and Scope
#!/bin/bash
# Function definition
greet_user() {
# 'local' makes the variable accessible only within this function
local guest_name=$1
echo "Hello, $guest_name!"
}
# Invoking the function and passing an argument
greet_user "Charlie"
Return Values
Functions in Bash do not return data values in the traditional sense. Instead, they return an exit status code (0 to 255) using the return keyword, or output text which can be captured.
Option 1: Using Return Status Codes (Numeric)
check_status() {
return 1 # Signifies a specific error or state
}
check_status
status=$?
echo "The exit status was: $status"
Option 2: Returning String Output
get_greeting() {
echo "Welcome back!"
}
# Capture the printed output of the function
message=$(get_greeting)
echo "Message: $message"
8. Arrays
Bash supports one-dimensional arrays.
Indexed Arrays
# Define an array
colors=("red" "green" "blue")
# Access elements (index starts at 0)
echo "First color: ${colors[0]}"
# Access all elements
echo "All colors: ${colors[@]}"
# Get the length of the array
echo "Array size: ${#colors[@]}"
# Append an element
colors+=("yellow")
9. Arithmetic Operations
By default, Bash treats variables as strings. To perform math, you need to use specific constructs.
Double Parentheses (( ... ))
This is the standard way to perform integer arithmetic in Bash.
num1=15
num2=5
sum=$((num1 + num2))
difference=$((num1 - num2))
product=$((num1 * num2))
quotient=$((num1 / num2)) # Integer division
echo "Sum: $sum"
echo "Quotient: $quotient"
Floating-Point Arithmetic
Bash does not natively support decimal calculations. For non-integers, pipe the expression to bc (Basic Calculator).
# Scale sets the number of decimal places
result=$(echo "scale=2; 10 / 3" | bc)
echo "Result: $result" # Outputs 3.33
10. Redirection and Pipelines
Standard Streams
stdin(Standard Input) - File descriptor 0stdout(Standard Output) - File descriptor 1stderr(Standard Error) - File descriptor 2
Redirection Operators
>: Overwrites output to a file.>>: Appends output to a file.2>: Redirects error output.&>: Redirects both standard output and standard error.<: Reads input from a file.
Examples:
# Redirect output to a file (overwrites existing content)
echo "Line 1" > output.txt
# Append to a file
echo "Line 2" >> output.txt
# Redirect error messages to a file
ls non_existent_dir 2> error.log
# Discard both output and error output entirely
command_name &> /dev/null
Pipelines
Pipes (|) allow you to pass the stdout of one command as the stdin to another command.
# List files, filter for those containing "log", and count the lines
ls | grep "log" | wc -l
11. Debugging and Error Handling
Writing clean, robust Bash scripts requires proactive error checking.
Common Debugging Flags
You can enable debugging options within your script by placing them near the top.
# Enable these options at the start of your script
set -e # Terminate script immediately if any command returns a non-zero status.
set -u # Treat unset variables as an error and exit immediately.
set -o pipefail # Catch errors occurring within a pipeline of commands.
Or combining them:
#!/bin/bash
set -euo pipefail
Debugging Line-by-Line
To see exactly what commands Bash executes, use the -x option:
- On execution:
bash -x script.sh - Within the script:
set -x # Turn on debugging output
echo "This part is being debugged"
set +x # Turn off debugging output
Standard Exit Codes
Always exit your script with an appropriate exit code.
if [[ -f "important_file.txt" ]]; then
echo "File found."
exit 0 # Success
else
echo "Critical file missing." >&2
exit 1 # Failure
fi
The guide was created in June 2026.