How to Create a Bash Script

How to Create a Bash Script

The first script I ever wrote was just three lines long, but it saved me from typing the same five commands every single morning. That’s really the whole point of Bash scripting — automating repetitive work. In this guide, I’ll walk you through the complete process of creating a Bash script from scratch, step by step, including everything you need to make it actually runnable.

What Is a Bash Script?

A Bash script is simply a plain text file containing a sequence of commands that Bash can execute, one after another, exactly as if you’d typed them into the terminal yourself. Instead of running commands manually every time, you save them once and run the whole file whenever you need to.

Step 1: Open a Text Editor

You can write a Bash script using any plain text editor — nano, vim, gedit, VS Code, or even a graphical text editor. I’ll use nano here since it’s beginner-friendly and available on almost every Linux system.

nano myscript.sh

This opens a new (or existing) file named myscript.sh in the nano editor. The .sh extension isn’t strictly required by Bash itself, but it’s a strong convention that immediately tells anyone browsing your files that this is a shell script.

Step 2: Add the Shebang Line

The very first line of your script should be the shebang, which tells the system which interpreter to use to run the file.

#!/bin/bash

This line must be the absolute first line — no blank lines or spaces before it — or the system won’t recognize it correctly.

Step 3: Write Your Commands

Below the shebang, add whatever commands you want the script to execute, one per line.

#!/bin/bash

echo "Starting the script..."
echo "Current date and time:"
date
echo "Files in this directory:"
ls
echo "Script finished."

Save the file. In nano, that’s Ctrl+O to write out, then Enter to confirm, and Ctrl+X to exit.

Step 4: Make the Script Executable

Before you can run the script directly, you need to give it execute permission using chmod.

chmod +x myscript.sh

What this does: chmod (change mode) modifies the file’s permission bits. The +x flag adds execute permission for the file, allowing it to be run as a program rather than just opened as plain text.

You can confirm the permission was applied using:

ls -l myscript.sh

Output:

-rwxr-xr-x 1 user user 145 Jul 28 14:00 myscript.sh

Notice the x characters in the permission string (rwxr-xr-x) — those confirm execute permission is now set for the owner, group, and others.

Step 5: Run the Script

There are two common ways to run a Bash script.

Method 1: Using ./

./myscript.sh

Output:

Starting the script...
Current date and time:
Tue Jul 28 14:32:10 UTC 2026
Files in this directory:
myscript.sh
Script finished.

The ./ tells the shell explicitly to look for the script in the current directory, since Bash doesn’t search the current directory by default for security reasons.

Method 2: Running It Through Bash Directly

bash myscript.sh

This works even if the file doesn’t have execute permission, since you’re explicitly telling Bash to interpret the file rather than trying to execute it as a standalone program.

Step 6: Add Structure — Variables, Input, and Logic

A real-world script usually does more than print static text. Let’s build one that actually does something useful.

#!/bin/bash

# A simple script to back up a folder

echo "Enter the folder path you want to back up:"
read source_folder

if [ ! -d "$source_folder" ]
then
    echo "Error: That folder does not exist."
    exit 1
fi

timestamp=$(date +%Y%m%d_%H%M%S)
backup_name="backup_$timestamp.tar.gz"

tar -czf "$backup_name" "$source_folder"

echo "Backup created: $backup_name"

Sample run:

Enter the folder path you want to back up:
/home/user/documents
Backup created: backup_20260728_143520.tar.gz

This script:

  1. Asks the user for a folder path
  2. Checks whether that folder actually exists using -d
  3. Exits with an error message if it doesn’t
  4. Builds a timestamped filename for the backup
  5. Compresses the folder into a .tar.gz archive
  6. Confirms the backup was created

Step 7: Passing Arguments to a Script

Instead of always prompting for input, scripts can accept arguments directly from the command line.

#!/bin/bash

echo "You are backing up: $1"
tar -czf "backup.tar.gz" "$1"
echo "Done!"

Sample run:

$ ./backup.sh /home/user/photos
You are backing up: /home/user/photos
Done!

Step 8: Adding Error Handling

Good scripts check whether things actually succeeded before moving on.

#!/bin/bash

mkdir /some/protected/folder

if [ $? -ne 0 ]
then
    echo "Failed to create folder. Check your permissions."
    exit 1
fi

echo "Folder created successfully."

$? holds the exit status of the last command — 0 means success, anything else means it failed.

Step 9: Running a Script from Anywhere

If you want to run your script by name from any directory (without typing ./ or the full path), move it into a directory listed in your PATH, such as /usr/local/bin, and make sure it’s executable.

sudo mv myscript.sh /usr/local/bin/myscript
sudo chmod +x /usr/local/bin/myscript

Now you can simply type:

myscript

from any location in the terminal.

How This Works Internally

  • When you run ./myscript.sh, the shell asks the kernel to execute the file. The kernel reads the first two bytes; if they’re #!, it looks at the rest of that line to determine the interpreter (/bin/bash in our case) and hands the file off to it.
  • chmod +x sets the executable bit in the file’s permission metadata, stored as part of the filesystem’s inode information — without this bit, the kernel refuses to execute the file directly, even if its content is valid Bash.
  • When you run bash myscript.sh instead, you’re bypassing the executable-bit requirement entirely, since you’re explicitly launching the bash interpreter and handing it the script file as an argument.
  • $? is set automatically by Bash after every command completes, reflecting that command’s exit status — this is a core mechanism used throughout error handling in scripts.

Real-World Use Cases

  • Automated backups, as shown above.
  • Deployment scripts that pull the latest code, install dependencies, and restart a service.
  • System maintenance scripts that clean up old log files, check disk space, or rotate backups.
  • Environment setup scripts that install and configure everything a new developer machine needs in one run.

Best Practices

  • Always start with a shebang line (#!/bin/bash).
  • Use meaningful script names that describe what they do (backup_database.sh, not script1.sh).
  • Include comments explaining the script’s purpose, especially near the top.
  • Validate input and check command exit statuses ($?) before proceeding to the next step.
  • Use set -e at the top of critical scripts to make the whole script exit immediately if any command fails, preventing cascading errors.

Security Considerations

  • Never store passwords or API keys in plain text inside a script; use environment variables or a secrets manager instead.
  • Be cautious about giving scripts execute permission for everyone (chmod 777) — restrict permissions to only what’s needed (chmod 750, for example).
  • Validate any input used to build filenames or paths, to avoid accidental (or malicious) path traversal.
  • Avoid running scripts as root unless absolutely necessary, and audit any script before running it with elevated privileges.

Optimization Tips

  • Break large scripts into functions for readability and reusability, rather than one long sequential list of commands.
  • Avoid unnecessary subshells and external command calls inside loops — prefer Bash builtins where possible.
  • Use shellcheck (a popular static analysis tool for shell scripts) to catch common mistakes and inefficiencies before running your script in production.

Troubleshooting Common Issues

  • “Permission denied” when running the script — you forgot to run chmod +x on the file.
  • “bad interpreter: No such file or directory” — usually caused by incorrect line endings (Windows-style \r\n instead of Unix \n) in the shebang line; convert the file using dos2unix if needed.
  • Script runs but has no effect — double-check you’re running the version you just edited and not an older cached copy, and verify file paths are correct.
  • “command not found” for a command you know exists — check that the command’s directory is included in your PATH environment variable.

Frequently Asked Questions

Q: Do Bash scripts need the .sh extension? A: No, it’s just a naming convention. Bash doesn’t require it, but it’s helpful for readability and tooling.

Q: What’s the difference between running ./script.sh and bash script.sh? A: ./script.sh requires the execute permission bit to be set and relies on the shebang line; bash script.sh explicitly invokes Bash regardless of the execute permission.

Q: How do I run a script automatically at startup or on a schedule? A: Use cron for scheduled tasks (crontab -e) or add it to your system’s startup services for boot-time execution.

Q: Can a Bash script call another Bash script? A: Yes, simply reference it by path, e.g., ./other_script.sh, or use source other_script.sh if you want it to run within the same shell session.

Common Mistakes to Avoid

  • Forgetting to make the script executable before trying to run it directly.
  • Leaving out the shebang line, causing inconsistent behavior across different systems.
  • Not validating user input or command success before proceeding.
  • Hardcoding paths or values that should really be variables or arguments.

Summary

Creating a Bash script is straightforward: write your commands in a plain text file, add a shebang line at the top, make the file executable with chmod +x, and run it. From there, the real skill lies in structuring your script well — using variables, handling input, checking for errors, and documenting your intentions clearly. Once you’ve built a handful of scripts this way, automating your daily workflow becomes second nature.

References

Total
2
Shares

Leave a Reply

Previous Post
How to Open the Bash Shell

How to Open the Bash Shell

Next Post
How to Comment Your Bash Script

How to Comment Your Bash Script

Related Posts