Making a Script Executable
You've written a brilliant shell script and added the perfect shebang. You try to run it with
./my_script.sh and get this frustrating error:
bash: ./my_script.sh: Permission denied
Why? Because, by default, a new file is created with read and write permissions for the owner, but not execute permission. The system protects you from accidentally running a text file as a program.
To turn your text file into a command you can run, you need to give it the execute permission.
The Tool: chmod (Change Mode)
We use the chmod command, which we learned about in the File Permissions module,
to add the execute bit.
Symbolic notation:
u– user (owner)g– groupo– othersa– all (user + group + others)+– add permissionx– execute permission
How to Make a Script Executable
Step 1: Check the Current Permissions
Use ls -l to view permissions.
ls -l my_script.sh -rw-r--r-- 1 user user 123 Jan 16 11:30 my_script.sh
The first string -rw-r--r-- shows the permissions.
Since there is no x, the script cannot be executed.
Step 2: Add Execute Permission
Option 1: Make executable for the owner only
chmod u+x my_script.sh
u+x means add execute permission for the user/owner.
Option 2: Make executable for everyone
chmod a+x my_script.sh
or the common shortcut:
chmod +x my_script.sh
a+x adds execute permission for all users.
Step 3: Verify the Change
Check the permissions again.
ls -l my_script.sh -rwxr--r-- 1 user user 123 Jan 16 11:30 my_script.sh
or if executable for everyone:
-rwxr-xr-x 1 user user 123 Jan 16 11:30 my_script.sh
The presence of x means the file can now be executed.
Step 4: Run the Script
# Run script from the current directory ./my_script.sh
If the script is inside a directory listed in your $PATH (such as ~/bin),
you can run it directly:
my_script.sh
Why Use Variables?
Variables are like labeled boxes where you can store information (text, numbers, filenames) for your script to use later.
They are essential for:
- Avoiding repetition: Store a value once and reuse it many times.
- Making scripts configurable: Use variables for values that may change.
- Capturing output: Store the result of a command to reuse in your script.
Using Variables in Bash
1. Setting a Variable (The Box Label)
To create a variable, choose a name and assign a value using the = operator.
No spaces are allowed around the equals sign.
# Store text name="Alice" filename="report.txt" # Store a number count=42 # Store command output current_date=$(date)
2. Using a Variable (Accessing the Value)
To access the value inside a variable, prefix the variable name with a $.
# Print the variable value echo "Hello, $name" # Use the variable inside a command cp $filename /backup/$filename
You can also use curly braces {} to clearly separate variable names
from surrounding text. This is called parameter expansion.
# Without braces (incorrect)
echo "The file is $filename_backup"
# With braces (correct)
echo "The file is ${filename}_backup"
3. Important Rules
- Variable names are case-sensitive.
$nameand$NAMEare different. - By convention: uppercase for constants, lowercase for script variables.
- No spaces around the equals sign.
count=42is correct, butcount = 42causes an error.
Command Substitution: $(command)
Command substitution allows you to capture the output of a command and store it inside a variable.
Syntax:
variable_name=$(command_to_run)
Examples
# Store the current date and time current_time=$(date) echo "The script started at $current_time" # Store the system hostname server_name=$(hostname) echo "Running on server: $server_name" # Count number of lines in a file line_count=$(wc -l < /etc/passwd) echo "There are $line_count users on the system." # Store a configuration file path config_file=$(find /etc -name "nginx.conf" 2>/dev/null | head -1) echo "Found config at: $config_file"
Control Structures in Bash
What are Control Structures?
So far, our scripts have run commands in a straight line. Control structures change this flow. They allow scripts to make decisions, repeat tasks, and choose different paths based on conditions.
This transforms a simple list of commands into a powerful program.
The two main types of control structures are:
- Conditionals: Execute code based on conditions (
if,case). - Loops: Repeat commands multiple times (
for,while,until).
1. Conditional Execution: The if Statement
The if statement allows a script to make decisions.
Basic logic: "If this condition is true, execute the commands."
Basic Syntax
if [ condition ]; then # commands to run if condition is TRUE fi
if-else Syntax
if [ condition ]; then # commands if TRUE else # commands if FALSE fi
if-elif-else Syntax
if [ condition1 ]; then # commands if condition1 is TRUE elif [ condition2 ]; then # commands if condition2 is TRUE else # commands if all conditions are FALSE fi
Example: Safe File Deletion
#!/bin/bash filename="$1" if [ -f "$filename" ]; then echo "File found. Deleting $filename..." rm "$filename" else echo "Error: File '$filename' does not exist." fi
2. The case Statement
The case statement is useful when comparing a variable against multiple patterns.
It works like a multi-choice if statement.
Syntax
case $variable in
pattern1)
# commands
;;
pattern2)
# commands
;;
*)
# default commands
;;
esac
Example: Simple Menu System
#!/bin/bash
echo "Select an option: start|stop|status"
read choice
case $choice in
start)
echo "Starting the service..."
systemctl start my-service
;;
stop)
echo "Stopping the service..."
systemctl stop my-service
;;
status)
echo "Checking status..."
systemctl status my-service
;;
*)
echo "Error: Invalid option. Use start, stop, or status."
exit 1
;;
esac
3. Loops: Automating Repetition
A. The for Loop
The for loop is used to iterate through a list of items.
Syntax
for item in list_of_items; do # commands done
Example
#!/bin/bash # Script to greet friends for name in Alice Bob Charlie; do echo "Hello, $name! How are you today?" done
Output
Hello, Alice! How are you today? Hello, Bob! How are you today? Hello, Charlie! How are you today?
B. The while Loop
The while loop runs commands repeatedly while a condition is true.
Syntax
while [ condition ]; do # commands done
Example: Countdown Timer
#!/bin/bash count=5 while [ $count -gt 0 ]; do echo "T-minus $count..." sleep 1 count=$((count - 1)) done
Output
T-minus 5... T-minus 4... T-minus 3... T-minus 2... T-minus 1...
C. The until Loop
The until loop runs commands until a condition becomes true.
It works opposite to the while loop.
Syntax
until [ condition ]; do # commands done
Example: Wait for a Website to Respond
#!/bin/bash echo "Waiting for example.com to come online..." until ping -c 1 example.com &> /dev/null; do echo "Site is unreachable. Retrying in 3 seconds..." sleep 3 done echo "SUCCESS: example.com is now reachable!"
Output
Waiting for example.com to come online... Site is unreachable. Retrying in 3 seconds... Site is unreachable. Retrying in 3 seconds... SUCCESS: example.com is now reachable!