The Bash Scripting Guide Every Cybersecurity Beginner Needs

Bash is a core skill for anyone working with Linux systems, scripting, or automation. This guide gives beginners a solid, practical introduction to Bash — with a focus on real usage and cybersecurity applications rather than theory or memorization.

The Bash Scripting Guide Every Cybersecurity Beginner Needs cover

Bash is a core skill for anyone working with Linux systems, scripting, or automation. In cybersecurity especially, it is one of the primary tools used for task automation, system interaction, and rapid problem-solving. If you cannot comfortably work in Bash, your Linux knowledge is incomplete.

This guide is designed to give beginners a solid, practical introduction to Bash, with a focus on real usage rather than theory or memorization. Without further ado — let's get started.

Important This guide is aimed at security practitioners who want to learn Bash, but it will help you understand the language regardless of your career. It assumes you already have foundational Linux knowledge, including:
  1. Understanding how the file system works in UNIX systems
  2. Knowing basic commands in the terminal

Module 1: Why Use Bash For Scripting

A Bash script is a file containing a sequence of commands executed by the Bash program line by line. It allows you to perform a series of actions — navigating to a directory, creating a folder, launching a process — using the command line. By saving these commands in a script, you can repeat the same sequence of steps multiple times simply by running the script.

Advantages of Bash scripting include:

📝
Note Most of the time "shell" and "bash" are used interchangeably, which is incorrect. The term "shell" refers to any program that provides a command-line interface for interacting with an operating system. Bash (Bourne-Again Shell) is the mainstream shell for most Linux distributions — more on this later.

Why Bash Matters in Cybersecurity

If you can't script in Bash, you're handicapped on Linux systems. And Linux runs the internet.

Setup of the Script

Bash scripts often use the .sh extension, however Linux is not Windows — extensions are mostly conventions here. There are 2 much more crucial points to consider.

  1. Shebang. Bash scripts start with a shebang — a combination of bash # and bang ! followed by the Bash shell path. This is the first line of the script and tells the shell to execute it via Bash. First, find where your Bash interpreter is located:

    BASH
    which bash
    /usr/bin/bash # my response

    Now write #!/usr/bin/bash at the top of your script file. Note that yours might be located elsewhere, so don't skip this command.

  2. Permission to Execute. A file must have execute permission. Run:

    BASH
    chmod +x script.sh

    Done.

If both conditions are met you can run even extensionless files. Now let's get our hands dirty.

Module 2: Syntax

Have you ever thought of something that's both confusing and easy? That's Bash syntax. You probably already guessed — # is used for commenting. Everything after it on the same line is ignored.

Important Syntax is only explained in this module. The practical use of the mentioned points comes later — so if you don't understand something now, you will understand it better in the next module.

1. Variables and Assignment

In Bash, variables are assigned simply:

BASH
VAR=value
# "VAR" is the name and "value" is the content

To get the value, use the $ prefix — like echo $VAR. Note that if the variable has spaces, Bash will separate them into arguments instead of treating them as a single string. To avoid this, wrap the variable in "": echo "$VAR".

Use curly braces {} to indicate where the variable name ends:

BASH
name="John"
echo "${name} Doe"

Without them, Bash would try to find the wrong variable and fail. You can also use unset VAR to delete a variable. Note that there should be no spaces when assigning — VAR = "value" will not work.

2. Quoting and Command Substitution

Bash handles text differently depending on how you quote it:

BASH
echo "Today is $(date)"

Here, $(date) runs the date command, and Bash replaces it with whatever that command outputs.

3. Command and Execution

If you know what commands are (which you must) and know some commands yourself (which you should), you can integrate them directly into your script. You can also chain commands:

BASH
git clone https://github.com/bestrepoever.git && cd bestrepoever
# The second command will run only if the first succeeded.
sudo dnf install btop || sudo dnf install htop
# The second command will run only if the first fails.
# I use Fedora btw :3

4. Conditionals

The standard conditional in Bash starts with if, checks a condition, and then runs commands:

BASH
if [ condition ]; then
    commands
elif [ another_condition ]; then
    commands
else
    commands
fi

The [ ] are actually a special Bash command called test. The spaces around the brackets are mandatory. For example:

BASH
num=10
if [ "$num" -gt 5 ]; then
    echo "Greater than 5"
else
    echo "5 or less"
fi

Here, -gt means "greater than". Bash checks if $num is bigger than 5 and runs the appropriate branch.

[[ ]] is a safer Bash-only version. Inside it, you don't have to worry about quoting variables or weird word splitting, and it supports pattern matching:

BASH
filename="test.txt"
if [[ $filename == *.txt ]]; then
    echo "This is a text file"
fi

== *.txt checks if $filename ends with .txt.

Diagram showing Bash conditional flow — if, elif, else, fi with test brackets
Bash conditional structure — [ ] (test) vs [[ ]] (Bash extended test)

5. Loops

Loops let you repeat commands. Bash has multiple types:

6. Functions

Functions are reusable bundles of commands:

BASH
#!/usr/bin/bash

# Define a function that greets a user
greet_user() {
    local name=$1       # $1 is the first argument passed to the function
    local age=$2        # $2 is the second argument
    echo "Hello, $name! You are $age years old."
    echo "Number of arguments passed to this function: $#"
    echo "All arguments: $@"
}

# Call the function with arguments
greet_user "John" 17
greet_user "Jane" 25

Explanation:

  1. greet_user() defines the function.
  2. Inside the function: local name=$1 grabs the first argument passed when calling the function. local age=$2 grabs the second. $# counts how many arguments were passed. $@ expands to all arguments. We call it twice with different names and ages.
  3. Using local ensures name and age exist only inside the function — outside, they don't exist.

Module 3: Data, I/O, and Script Safety

Now that we have a handle on Bash syntax, we can move to more advanced subtopics.

1. Arrays

Arrays store multiple values in one variable:

BASH
array=(one two three)
echo ${array[0]}       # prints first element: one
echo "${array[@]}"     # prints all elements safely: one two three

"${array[@]}" keeps each element as-is, even if it contains spaces. Without quotes, Bash splits each word separately.

There are also associative arrays (like dictionaries):

BASH
declare -A assoc
assoc[name]="John"
assoc[age]=17
echo ${assoc[name]}    # prints John
📝
Note If you're unfamiliar with associative arrays (dictionaries) — they are like lists, but they consist of key: value pairs.

declare is needed for making a special variable and -A tells Bash that this is an associative array. assoc is the name of the array.

2. Redirection

Redirection tells Bash where input comes from and where output goes:

BASH
echo "Hello" > file.txt             # send output to file.txt, overwrite
echo "Hello again" >> file.txt      # append output
ls nonexistent 2> error.log         # redirect error messages
ls > output.log 2>&1               # redirect both stdout and stderr
cat < file.txt                      # reads input from a file
cat file.txt | grep "Joshua"        # output of first command becomes input of second
diff <(ls dir1) <(ls dir2)         # process substitution — makes output look like a file
# Here it compares two directories as if they are files (diff won't work otherwise)

3. Parameter Expansion

Bash can work with variables in advanced ways:

BASH
echo ${VAR:-default}   # if VAR is empty, use "default"
echo ${VAR:=default}   # if VAR is empty, set it to "default"
echo ${VAR:+other}     # if VAR exists, use "other"
echo ${VAR:?error}     # exit script if VAR is empty

We can also do string manipulation:

BASH
text="HelloWorld"
echo ${text:0:5}             # first 5 characters (starts from 0) → Hello
filename="file.txt"
echo ${filename%.*}          # remove extension → file
sentence="one two one"
echo ${sentence//one/three}  # replace all 'one' → three two three

4. Arithmetic

One of the main differences between you and Bash is that it can do math:

BASH
((a = 5 + 3))   # sets a to 8
((a++))         # increment by 1 → a=9
b=$((a * 2))    # b=18
BASH
if (( a > 10 )); then
  echo "Greater than 10"
fi

5. Special Variables

Bash has built-in variables you can use everywhere:

📝
Note Exit codes follow a convention: 0 means success, 1–255 indicate various failures. This matters when chaining commands or checking if operations succeeded.
BASH
echo "Script name: $0"
echo "First argument: $1"
echo "Number of arguments: $#"
# And so on

6. Error Handling

Your scripts will fail sooner or later for various reasons — half the time it won't even be your fault. The interesting thing about Bash is that by default it will continue running after an error, which can sometimes be dangerous.

  1. Exit on Error

    BASH
    set -e
    # Script exits immediately if any command fails (returns non-zero exit code)

    set -e prevents cascading failures.

  2. Exit on Undefined Variables

    BASH
    set -u
    # Script exits if you reference a variable that doesn't exist

    This catches typos. If you write $USRNAME instead of $USERNAME, Bash will error out instead of silently treating it as empty.

  3. Pipefail

    BASH
    set -o pipefail
    # Makes pipelines return the exit code of the first failed command

    Normally, command1 | command2 only checks if command2 succeeded. With pipefail, if command1 fails, the whole pipeline fails.

  4. Combine Them (Best Practice)

    BASH
    #!/usr/bin/bash
    set -euo pipefail
    # Now your script is strict: no silent failures, no undefined variables, no broken pipes
  5. Check Exit Codes Manually

    BASH
    if ! ping -c 1 192.168.1.1 &>/dev/null; then
        echo "Host is down"
        exit 1
    fi

    $? holds the exit code of the last command (0 = success, anything else = failure). You can check it directly:

    BASH
    ping -c 1 192.168.1.1
    if [ $? -ne 0 ]; then
        echo "Ping failed"
    fi
  6. Trap Errors

    BASH
    trap 'echo "Error occurred on line $LINENO"' ERR

    This catches errors and tells you exactly where they happened. Useful for debugging long scripts.

  7. Example: Robust Script Template

    BASH
    #!/usr/bin/bash
    set -euo pipefail
    
    # Trap errors and show line number
    trap 'echo "Error on line $LINENO. Exiting." >&2' ERR
    
    # Check if required command exists
    if ! command -v nmap &>/dev/null; then
        echo "nmap is not installed. Install it first."
        exit 1
    fi
    
    # Your actual script logic here
    echo "Script running safely..."

    Key takeaway: Always use set -euo pipefail at the top of your scripts unless you have a specific reason not to. It saves you from debugging silent failures later.

Module 4: Example Code and Conclusion

Here is a complete script that puts everything together so you can see what goes where:

BASH
#!/usr/bin/bash
set -euo pipefail
trap 'echo "Error on line $LINENO" >&2' ERR

# 1. Variables + parameter expansion
USER_NAME="${1:-Martin}"     # default if not provided
AGE=17
unset TEMP_VAR || true

# 2. Quoting + command substitution
TODAY="$(date)"
echo "User: $USER_NAME"
echo "Today is $TODAY"
echo 'This $WILL not expand'

# 3. Command chaining
mkdir -p demo_dir && cd demo_dir || exit 1

# 4. Conditionals
if [[ "$USER_NAME" == M* ]]; then
    echo "Name starts with M"
else
    echo "Name does not start with M"
fi

# 5. Loops
for i in 1 2 3; do
    echo "For loop value: $i"
done

count=1
while (( count <= 2 )); do
    echo "While loop count: $count"
    ((count++))
done

# 6. Function
greet() {
    local name="$1"
    echo "Hello, $name"
    echo "Args count: $#"
}
greet "$USER_NAME"

# 7. Arrays
tools=(nmap curl git)
echo "First tool: ${tools[0]}"
echo "All tools: ${tools[@]}"

declare -A person
person[name]="$USER_NAME"
person[age]=$AGE
echo "Assoc name: ${person[name]}"

# 8. Redirection + pipes
echo "log entry" > output.log
ls nonexistent 2> error.log || true
cat output.log | grep log > filtered.log

# 9. String parameter expansion
FILE="report.txt"
echo "Filename without ext: ${FILE%.*}"

TEXT="one two one"
echo "${TEXT//one/three}"

# 10. Arithmetic
((x = 5 + 3))
((x++))
y=$((x * 2))
echo "Math result: $y"

# 11. Special variables
echo "Script: $0"
echo "Args: $@"
echo "PID: $$"

# 12. Manual error check
if ! command -v git &>/dev/null; then
    echo "git missing"
    exit 1
fi

echo "Script finished cleanly"

The output will be:

TEXT
User: Martin
Today is Sat Jan 24 02:34:14 PM +04 2026
This $WILL not expand
Name starts with M
For loop value: 1
For loop value: 2
For loop value: 3
While loop count: 1
While loop count: 2
Hello, Martin
Args count: 1
First tool: nmap
All tools: nmap curl git
Assoc name: Martin
Filename without ext: report
three two three
Math result: 18
Script: ./test.sh
Args:
PID: 15634
Script finished cleanly

Toy around with this script to understand every part of it.

Conclusion

Bash is an essential tool in cybersecurity, but we are far from done yet. A real security practitioner must be able to chain tools, automate workflows, and extract maximum value from simple commands. That level comes later.

The next step is Python. A cybersecurity-focused Python methodology will be released in early February — and after you understand both languages, it will be time to combine them by writing a program that will be useful as a portfolio project or simply for personal use. Thank you for your time.


Warning Only use these skills on systems you own or have explicit written permission to interact with.
Back to Articles