Bash Scripting Series — Level 2
Bash Scripting Series — Level 2: Directory Validation and Conditional Statements
Introduction
In Level 1, we explored the Linux command line and learned how to navigate the filesystem and execute basic commands.
In Level 2, we begin writing scripts that make decisions based on specific conditions.
Consider a script that saves security scan results to a directory. Before saving anything, it should verify that the destination exists. This helps prevent avoidable errors and makes the script more reliable.
In this lesson, we will build a directory validation script and explore the Bash concepts behind it, how to run and test it, and how to expand it into a more useful tool.
1. The Original Script
#!/bin/bash
# Ask the user for a directory path
read -p "Enter a directory path: " dir
# Check whether input was provided
if [ -z "$dir" ]; then
echo "Error: No directory path provided."
exit 1
fi
# Check whether the directory exists
if [ -d "$dir" ]; then
echo "Directory exists: $dir"
exit 0
else
echo "Directory does not exist: $dir"
exit 2
fiThe script follows five steps:
Collect a directory path from the user.
Reject empty input.
Check whether the path identifies an existing directory.
Display the appropriate result.
Return an exit status indicating the outcome.
Let's examine the components that make this possible.
2. Understanding the Script
The Shebang
#!/bin/bashThe shebang identifies the interpreter used when the script is executed directly. Here, it specifies Bash, which provides features such as variables, conditional statements, loops, and functions.
Reading User Input
read -p "Enter a directory path: " dirThe read command accepts input, while -p displays a prompt. The variable dir stores whatever the user enters.
For example, if the user enters:
/home/kali/DesktopThe variable contains that path, which can subsequently be accessed with $dir.
This script uses interactive input, not command-line arguments. We will explore the alternative later.
Checking for Empty Input
if [ -z "$dir" ]; then
echo "Error: No directory path provided."
exit 1
fiAn if statement allows Bash to execute commands conditionally.
The expression [ -z "$dir" ] checks whether the variable contains an empty string. The -z operator returns true when the string has zero length.
If the user presses Enter without typing a path, the script prints an error and executes exit 1.
The exit command terminates the script and returns a status to the calling process. Because the script exits here, it never reaches the directory check.
The general structure of a Bash conditional is:
if [ condition ]; then
# Commands when the condition is true
else
# Commands when the condition is false
fiThe else branch is optional, and fi closes the conditional statement.
Checking Whether the Directory Exists
if [ -d "$dir" ]; then
echo "Directory exists: $dir"
exit 0
else
echo "Directory does not exist: $dir"
exit 2
fiThe -d test checks whether the path exists and refers to a directory.
This distinction matters because a path can exist without being a directory. For example, /etc/passwd is normally a regular file, so [ -d "/etc/passwd" ] evaluates to false.
When the test succeeds, the script prints a confirmation and exits with status 0. Otherwise, it prints a message and returns status 2.
Notice the quotes around "$dir". They preserve the path as a single argument, including when it contains spaces. For example, /home/kali/My Projects must be treated as one path rather than two separate words.
3. Understanding Exit Codes
An exit code communicates the result of a command or script to whatever launched it. Conventionally, 0 means success, while a non-zero value indicates a failure or another unsuccessful outcome.
Our script assigns these meanings:
| Exit code | Meaning in this script |
|---|---|
0 | The directory exists. |
1 | The user supplied no path. |
2 | The supplied path is not an existing directory. |
These are meanings chosen by our script; other programs may use the same numbers differently.
Checking the Return Status
Bash stores the previous command's exit status in $?.
Run the script and then inspect its result:
./directory_check.sh
echo $?If you enter an existing directory, the status is 0. Empty input returns 1, while a missing directory returns 2.
Run echo $? immediately after the script, because executing another command first can overwrite the status you intended to inspect.
4. Running the Script in Linux
You can follow these steps on Ubuntu, Kali Linux, or another typical Linux distribution.
Step 1: Create the File
Open a terminal and run:
nano directory_check.shPaste the script into Nano.
Save with Ctrl + O, press Enter, and exit using Ctrl + X.
Step 2: Make It Executable
chmod +x directory_check.shThe chmod command changes file permissions, and +x adds execute permission.
Step 3: Run It
./directory_check.shAlternatively, execute it through Bash:
bash directory_check.shThe second method does not require the script file itself to have execute permission.
Step 4: Test Different Scenarios
Use the following cases to verify the script's behavior.
Test A — Existing directory
Enter a directory that exists on your computer, such as /home/kali if that path is available.
Expected output:
Directory exists: /home/kaliExpected exit code: 0.
Test B — Missing directory
Enter a path you know does not exist:
/tmp/directory-that-does-not-exist-12345Expected output:
Directory does not exist: /tmp/directory-that-does-not-exist-12345Expected exit code: 2.
Test C — Empty input
Run the script and press Enter without entering anything.
Expected output:
Error: No directory path provided.Expected exit code: 1.
Test D — Regular file
Enter:
/etc/passwdOn a typical Linux installation, this path identifies a file rather than a directory. The script should therefore report that the directory does not exist.
Testing these scenarios helps verify that both the conditions and the exit statuses work as intended.
5. Absolute and Relative Paths
The script accepts both absolute and relative paths.
An absolute path begins at the filesystem root:
/home/kali/DesktopA relative path is interpreted from the current working directory:
DesktopIf your current directory is /home/kali, the relative path Desktop refers to /home/kali/Desktop.
Use pwd to check your current working directory:
pwdRelative paths are convenient when working within a project directory, while absolute paths are often easier to use in automation because their intended location is explicit.
6. Where and Why Is Directory Validation Useful?
Checking prerequisites before performing an operation is a common scripting practice.
Saving scan results: A security script can verify that its output directory exists before attempting to save reports.
Managing logs: An administrative script can check its log directory before writing log files. Directory existence alone does not guarantee write permission, so further checks may be needed.
Creating backups: A backup script can verify that its source directory is available before beginning the backup process.
Automating security labs: Scripts used in CTFs, authorized testing environments, or defensive security projects can validate their working directories before processing collected information.
The purpose is the same in each case: detect problems early instead of allowing the script to proceed with invalid assumptions.
7. Expanding the Script
Once you understand the original script, you can extend it in several useful directions.
Expansion 1: Accept Command-Line Arguments
Instead of prompting for a path every time, we can let the user supply it when launching the script.
Bash provides positional parameters:
$0refers to the script's invocation name or path.$1contains the first argument.$2contains the second argument.$#contains the number of positional arguments.
Replace the original script with this version:
#!/bin/bash
if [ "$#" -gt 1 ]; then
echo "Usage: $0 [directory_path]"
exit 1
fi
if [ "$#" -eq 1 ]; then
dir="$1"
else
read -r -p "Enter a directory path: " dir
fi
if [ -z "$dir" ]; then
echo "Error: No directory path provided."
exit 1
fi
if [ -d "$dir" ]; then
echo "Directory exists: $dir"
exit 0
else
echo "Directory does not exist: $dir"
exit 2
fiThe script now supports two ways to provide input.
Supply the path directly:
./directory_check.sh /home/kaliFor a path containing spaces, quote the argument:
./directory_check.sh "/home/kali/My Projects"Or run the script without an argument to receive the interactive prompt:
./directory_check.shThe read -r command is used for interactive input because it preserves backslashes literally rather than treating them as escape characters.
This version is more convenient for repeated use and can also be called by other scripts.
Expansion 2: Check Permissions
A directory may exist but still be unsuitable for a particular operation. Bash provides additional tests for checking file types, existence, and access permissions.
| Test | Purpose |
|---|---|
-e | Checks whether a path exists. |
-f | Checks whether a path is a regular file. |
-d | Checks whether a path is a directory. |
-r | Checks whether the path is readable by the current process. |
-w | Checks whether the path is writable by the current process. |
-x | Checks whether a path is executable; for a directory, it tests search or traversal permission. |
-n | Checks whether a string is non-empty. |
-z | Checks whether a string is empty. |
The following example checks whether a directory exists and reports its access permissions.
#!/bin/bash
read -r -p "Enter a directory path: " dir
if [ -z "$dir" ]; then
echo "Error: No directory path provided."
exit 1
fi
if [ ! -d "$dir" ]; then
echo "Error: Directory does not exist: $dir"
exit 2
fi
echo "Directory exists: $dir"
if [ -r "$dir" ]; then
echo "Readable: Yes"
else
echo "Readable: No"
fi
if [ -w "$dir" ]; then
echo "Writable: Yes"
else
echo "Writable: No"
fi
if [ -x "$dir" ]; then
echo "Searchable: Yes"
else
echo "Searchable: No"
fi
exit 0The ! operator reverses the test. Therefore, [ ! -d "$dir" ] is true when the supplied path does not identify an existing directory.
The script checks permissions only after confirming that the directory exists. These tests are useful indicators, but they do not guarantee that a later operation will succeed because permissions and other restrictions may change.
Expansion 3: Create a Missing Directory
Sometimes we want a script to create a directory rather than stop when it is missing.
The mkdir command creates directories, and its -p option creates missing parent directories as needed.
mkdir -p -- "$dir"Here is a complete example:
#!/bin/bash
read -r -p "Enter a directory path: " dir
if [ -z "$dir" ]; then
echo "Error: No directory path provided."
exit 1
fi
if [ -d "$dir" ]; then
echo "Directory already exists: $dir"
exit 0
fi
if mkdir -p -- "$dir"; then
echo "Directory created successfully: $dir"
exit 0
else
echo "Error: Could not create directory: $dir"
exit 2
fiThe expression if mkdir -p -- "$dir"; then executes mkdir and checks its exit status. The script prints the corresponding message depending on whether directory creation succeeds.
The -- marks the end of command-line options, preventing a path beginning with a hyphen from being interpreted as an option.
For example, entering /tmp/bash-lab/output creates the directory and any missing parent directories. If creation fails because of permissions or another filesystem problem, the script reports the failure.
Always verify the intended destination before allowing a script to create or modify filesystem locations.
8. Common Mistakes
Missing Spaces in Conditions
Incorrect:
if [-d "$dir"]; thenCorrect:
if [ -d "$dir" ]; thenThe square brackets are part of a command, so the surrounding spaces are required.
Confusing Existence with Directory Type
The -e test checks whether a path exists, while -d specifically checks whether it is a directory. Choose the condition that matches the operation your script needs to perform.
Forgetting Variable Quotes
Prefer:
[ -d "$dir" ]over:
[ -d $dir ]Quoting preserves paths containing spaces and avoids unintended word splitting.
Misunderstanding exit
When launched normally, exit terminates the script, not the terminal from which you started it. However, sourcing a script into your current shell can cause its exit command to terminate that shell session. For these exercises, execute the file using ./directory_check.sh or bash directory_check.sh.
Relying Only on Preliminary Checks
Checking a directory's existence or permissions does not guarantee that a later operation will succeed. When running commands such as mkdir, a backup utility, or a file-writing operation, check the command's actual exit status too.
9. Practical Exercises
Complete these exercises in your Linux virtual machine.
Exercise 1 — Directory validation: Test the original script with an existing directory, a missing directory, and empty input. Record each exit code.
Exercise 2 — File validation: Modify the script to check for a regular file using -f instead of a directory using -d.
Exercise 3 — Permission checks: Extend the script to report whether the selected directory is readable, writable, and searchable.
Exercise 4 — Command-line arguments: Accept a directory path through $1, while retaining the interactive prompt when no argument is supplied.
Exercise 5 — Automatic directory creation: Create a script that makes the requested directory if necessary and handles creation errors.
Exercise 6 — Exit status handling: Write a second script that launches the directory checker and reacts to its returned status.
For the final exercise, consider how another script could distinguish successful validation from missing input or an invalid directory.
Conclusion
In this lesson, we developed a directory validation script using Bash variables, user input, conditional statements, file tests, and exit codes.
We then extended the script to accept command-line arguments, check permissions, and create missing directories. These techniques form the foundation of more reliable automation.
Next step: Practice combining conditional statements with loops and functions. These concepts will help you build more advanced scripts for system administration, log processing, backups, and security lab workflows.
Comments