Bash shell scripting lets you place Linux and Unix commands in a text file and run them as a reusable program. A Bash script can automate file operations, system checks, backups, application startup, text processing, and other command-line tasks.
This tutorial explains what Bash scripting is, how it differs from general shell scripting, and how to create, run, debug, and organize Bash scripts safely.
What Is Bash Shell Scripting?
Bash is a command-line shell and scripting language commonly available on Linux and other Unix-like systems. The name Bash stands for Bourne Again Shell.
When commands are entered directly in a terminal, Bash executes them interactively. When the same commands are saved in a file, Bash can execute them as a script. Bash scripts usually use the .sh filename extension, although the extension is optional.
Bash Scripting and Shell Scripting
Shell scripting is a general term for writing scripts for a command-line shell. Bash scripting refers specifically to scripts interpreted by Bash.
| Term | Meaning |
|---|---|
| Shell scripting | Scripting for any compatible shell, such as sh, Bash, Zsh, or KornShell. |
| Bash scripting | Scripting that uses Bash syntax and Bash-specific features. |
A script written only with portable POSIX shell syntax may run in several shells. A script that uses Bash arrays, [[ ]] tests, brace expansion, or other Bash-specific features should explicitly run with Bash.
Check Whether Bash Is Installed
Open a terminal and run the following command:
bash --version
You can also locate the Bash executable with:
command -v bash
A common result is /usr/bin/bash or /bin/bash. The exact path depends on the operating system.
Create and Run Your First Bash Script
Create a file named hello.sh in a text editor:
nano hello.sh
Add the following Bash code:
#!/usr/bin/env bash
echo "Hello from Bash"
The first line is called a shebang. It tells the operating system which interpreter should execute the file. Using /usr/bin/env bash asks the environment to locate Bash through the current PATH.
Save the file, make it executable, and run it:
chmod +x hello.sh
./hello.sh
The result is:
Hello from Bash
You may also run the script by passing it directly to Bash:
bash hello.sh
Running bash hello.sh does not require execute permission, but running ./hello.sh does.
Bash Comments, Commands, and Exit Status
A line beginning with # is treated as a comment, except when #! appears as the first line of a script.
#!/usr/bin/env bash
# Display the current date and working directory
date
pwd
Every command returns an exit status. By convention, 0 indicates success, while a nonzero value indicates an error or another unsuccessful condition. The special variable $? contains the exit status of the most recently executed command.
mkdir reports
echo "Exit status: $?"
Bash Variables and Quoting
Create a variable by assigning a value without spaces around the equals sign:
name="Asha"
project_directory="project files"
echo "Hello, $name"
echo "Directory: $project_directory"
Double quotes allow variable expansion. Single quotes preserve text literally.
language="Bash"
echo "Learning $language"
echo 'Learning $language'
The output is:
Learning Bash
Learning $language
Quote variable expansions unless you specifically require word splitting or wildcard expansion. For example, use "$project_directory" when a path may contain spaces.
Read User Input in a Bash Script
The read command accepts input from the terminal:
#!/usr/bin/env bash
read -r -p "Enter your name: " name
echo "Hello, $name"
The -r option prevents backslashes in the entered text from being treated as escape characters.
Pass Command-Line Arguments to Bash Scripts
Bash provides positional parameters for values passed after the script name:
$0contains the script name.$1,$2, and later variables contain individual arguments.$#contains the number of arguments."$@"represents all arguments while preserving their boundaries.
#!/usr/bin/env bash
if [[ $# -lt 1 ]]; then
echo "Usage: $0 <name>"
exit 1
fi
echo "Hello, $1"
Run the script with an argument:
./greet.sh "Ravi Kumar"
Use If Conditions in Bash
An if statement runs commands only when a condition succeeds.
if condition; then
commands
elif another_condition; then
commands
else
commands
fi
The following script checks whether a directory exists:
#!/usr/bin/env bash
directory="reports"
if [[ -d "$directory" ]]; then
echo "$directory exists"
else
echo "$directory does not exist"
fi
Common file test operators include:
| Test | Meaning |
|---|---|
-e path | The path exists. |
-f path | The path is a regular file. |
-d path | The path is a directory. |
-r path | The path is readable. |
-w path | The path is writable. |
-x path | The path is executable. |
-s path | The file exists and is not empty. |
Compare Strings and Numbers in Bash
Inside Bash conditional expressions, string and numeric comparisons use different operators.
username="admin"
count=12
if [[ "$username" == "admin" ]]; then
echo "Administrator account"
fi
if (( count >= 10 )); then
echo "Count is at least 10"
fi
Use [[ ]] for Bash string and file tests. Use (( )) for arithmetic conditions.
Repeat Commands with Bash Loops
Bash for loop
for file in *.txt; do
echo "Found: $file"
done
To process command-line arguments safely, iterate over "$@":
for argument in "$@"; do
echo "Argument: $argument"
done
Bash while loop
count=1
while (( count <= 5 )); do
echo "$count"
((count++))
done
Create Reusable Bash Functions
A function groups related commands under a reusable name:
#!/usr/bin/env bash
print_message() {
local message="$1"
echo "Message: $message"
}
print_message "Backup started"
The local keyword limits a variable to the current function. Function arguments are accessed through $1, $2, and other positional parameters.
Use Command Substitution and Arithmetic
Command substitution stores or embeds a command’s output:
current_date=$(date +%F)
echo "Today is $current_date"
Arithmetic expansion evaluates integer calculations:
price=40
quantity=3
total=$((price * quantity))
echo "Total: $total"
Redirect Bash Output and Build Pipelines
Redirection changes where a command reads input or writes output.
| Operator | Purpose |
|---|---|
> | Write standard output to a file, replacing its current contents. |
>> | Append standard output to a file. |
2> | Write standard error to a file. |
< | Read standard input from a file. |
| | Send one command’s output to another command. |
date > report.txt
echo "Completed" >> report.txt
find /tmp -type f 2> errors.log
printf '%s\n' apple banana avocado | grep '^a'
To redirect both standard output and standard error to the same file in Bash, use:
some_command > command.log 2>&1
Bash Arrays
Bash supports indexed arrays:
servers=("web-01" "web-02" "database-01")
echo "First server: ${servers[0]}"
for server in "${servers[@]}"; do
echo "Checking $server"
done
Use "${array[@]}" to expand all elements while preserving each element as a separate value.
A Practical Bash Backup Script
The following example validates a source directory and creates a compressed archive with a date-based filename:
#!/usr/bin/env bash
set -euo pipefail
source_directory="${1:-}"
backup_directory="${2:-./backups}"
if [[ -z "$source_directory" ]]; then
echo "Usage: $0 <source-directory> [backup-directory]" >&2
exit 1
fi
if [[ ! -d "$source_directory" ]]; then
echo "Source directory does not exist: $source_directory" >&2
exit 1
fi
mkdir -p "$backup_directory"
timestamp=$(date +%Y%m%d-%H%M%S)
source_name=$(basename "$source_directory")
archive_path="$backup_directory/${source_name}-${timestamp}.tar.gz"
tar -czf "$archive_path" -C "$(dirname "$source_directory")" "$source_name"
echo "Backup created: $archive_path"
Run it as follows:
chmod +x backup.sh
./backup.sh "/home/user/project files" "/home/user/backups"
The paths are quoted so that directory names containing spaces are handled correctly.
Handle Errors More Safely in Bash
Many Bash scripts begin with the following options:
set -euo pipefail
-eexits when an unhandled command fails.-utreats references to unset variables as errors.-o pipefailmakes a pipeline fail when any command in it fails.
These settings can expose errors early, but they do not replace explicit validation. Some commands legitimately return nonzero statuses, so error behavior should be tested for each script.
You can also define a cleanup function and run it when the script exits:
temporary_file=$(mktemp)
cleanup() {
rm -f "$temporary_file"
}
trap cleanup EXIT
Check Bash Script Syntax and Trace Execution
Check a script for syntax errors without executing it:
bash -n script.sh
Run a script with execution tracing:
bash -x script.sh
Bash prints expanded commands before executing them. To trace only part of a script, enable and disable tracing within the file:
set -x
some_command
another_command
set +x
Avoid tracing sections that process passwords, access tokens, or other sensitive values because expanded commands may expose them in terminal output or logs.
Common Bash Scripting Mistakes
- Adding spaces around variable assignment: write
name="Sam", notname = "Sam". - Leaving path variables unquoted: use
cd "$directory"so spaces and wildcard characters are handled correctly. - Using
$*instead of"$@": quoted"$@"preserves separate command-line arguments. - Assuming a command succeeded: inspect its exit status or place it in an
ifcondition. - Parsing
lsoutput: use shell globbing,find, or another tool designed for structured file selection. - Using an incorrect interpreter: a script containing Bash-specific syntax should use a Bash shebang and should not be run with
sh script.sh. - Running scripts as root unnecessarily: use the minimum permissions required for the task.
Useful Bash Commands for Scripts
| Command | Typical scripting use |
|---|---|
printf | Produce formatted and predictable output. |
read | Read user input or file data. |
test or [[ ]] | Evaluate file, string, and numeric conditions. |
grep | Search text for matching lines. |
sed | Transform text streams. |
awk | Process field-oriented text and reports. |
find | Locate files by path, type, name, time, or size. |
sort | Sort lines of text. |
cut | Extract selected fields or character ranges. |
tee | Write output to a file and display it at the same time. |
getopts | Process short command-line options. |
mktemp | Create temporary files or directories safely. |
When Bash Scripting Is a Good Choice
Bash is well suited to tasks that primarily coordinate command-line programs, files, processes, environment variables, and operating-system utilities. Typical uses include:
- Automating repeated terminal commands
- Creating deployment and build wrappers
- Checking files, services, disks, and processes
- Preparing backups and archives
- Filtering logs and text files
- Configuring development or server environments
- Running scheduled maintenance tasks
For large applications, complex data structures, extensive testing requirements, or cross-platform business logic, a general-purpose language such as Python may be easier to maintain. Bash remains useful for connecting commands and managing system-level workflows.
Bash Shell Scripting Best Practices
- Start Bash-specific scripts with
#!/usr/bin/env bashor a verified absolute Bash path. - Quote variable expansions, especially variables containing paths or user input.
- Use
"$@"when forwarding all script arguments. - Validate required files, directories, commands, and arguments before using them.
- Write errors to standard error with
>&2. - Return meaningful exit statuses with
exit. - Use functions to separate repeated or logically distinct tasks.
- Use
localfor variables that belong only to a function. - Create temporary files with
mktempand remove them withtrap. - Run
bash -nbefore executing a changed script. - Test scripts with filenames and directory names containing spaces.
- Use a Bash-aware static analysis tool such as ShellCheck during development when available.
Bash Shell Scripting FAQs
What is Bash shell scripting?
Bash shell scripting is the practice of saving Bash commands, conditions, loops, functions, and variables in a file so they can be executed as a reusable program.
Is Bash scripting the same as shell scripting?
Bash scripting is one type of shell scripting. Shell scripting may target Bash or another shell, while Bash scripting specifically uses the Bash interpreter and may include Bash-only features.
How do I create and run a Bash script?
Create a text file with a Bash shebang, add commands, run chmod +x script.sh, and execute it with ./script.sh. You can also run it directly with bash script.sh.
Why does a Bash script show permission denied?
The file may not have execute permission. Run chmod +x script.sh and then use ./script.sh. Also verify that the current directory or mounted filesystem allows execution.
Should Bash variables always be quoted?
Variable expansions should normally be enclosed in double quotes, such as "$file". Quoting prevents unintended word splitting and wildcard expansion. Arithmetic contexts and a few deliberate expansion cases follow different rules.
Bash Shell Scripting Editorial QA Checklist
- Confirm that every Bash-specific example uses a Bash shebang.
- Verify that variable assignments contain no spaces around
=. - Check that path variables and command-line arguments are quoted correctly.
- Confirm that output-only examples use the
outputcode class. - Test the first script with both
bash hello.shand./hello.sh. - Run
bash -nagainst each complete Bash script. - Test examples with a directory name containing spaces, such as
project files. - Confirm that error examples return a nonzero exit status.
- Review destructive commands and ensure they do not operate on unvalidated paths.
- Check that Bash-specific syntax is not described as portable to every shell.
TutorialKart.com