NewHalo Edge 3 is here: HTTP/3 everywhere and 42 edge locations.Learn more
Docs / Tools and troubleshooting

Write your first shell script for your server

Tools and troubleshooting8 min readUbuntu 24.04 LTS

A shell script is a text file full of commands that you run as one program. Scripts save you from typing the same steps again and again, such as a nightly backup or a cleanup. This guide walks through a small, safe backup script, and explains the building blocks: variables, conditions, and exit codes.

Before you begin

  • A VPS running Ubuntu 24.04 LTS and SSH access as a regular user, such as alex. The script runs as you, so it does not need sudo.
  • A folder to back up. This guide uses ~/site, which you can create for practice.
  • A text editor. This guide uses nano.

Step 1: Create a practice folder

Make a folder with a sample file so the backup has something to copy. The ~ symbol is a shortcut for your home folder.

mkdir -p ~/site ~/scripts
echo "hello" > ~/site/index.html

Step 2: Write the script

Create the file backup-site.sh in your scripts folder:

nano ~/scripts/backup-site.sh

Paste this content and save with Ctrl+O, Enter, then exit with Ctrl+X:

#!/usr/bin/env bash
# Back up ~/site into a timestamped archive in ~/backups.
set -euo pipefail

SRC="$HOME/site"
DEST="$HOME/backups"
STAMP="$(date +%F-%H%M)"
FILE="$DEST/site-$STAMP.tar.gz"

if [ ! -d "$SRC" ]; then
  echo "Source folder $SRC does not exist" >&2
  exit 1
fi

mkdir -p "$DEST"
tar -czf "$FILE" -C "$HOME" site
echo "Backup written to $FILE"

Here is what each part does:

  • #!/usr/bin/env bash is the shebang line. It tells the system to run the file with bash.
  • set -euo pipefail makes the script stop at the first error, instead of pushing on with broken data.
  • SRC="..." sets a variable. Use $SRC to read it back. Quotes keep paths with spaces safe.
  • $(date +%F-%H%M) runs a command and inserts its output, here a timestamp such as 2026-10-31-0930.
  • if [ ! -d "$SRC" ] is a condition. It is true when the folder does not exist, and the script then exits with an error.
  • >&2 sends the error message to the error stream, where people will see it.
  • tar -czf creates a compressed archive, and -C "$HOME" keeps paths inside it tidy.

Step 3: Make it executable and run it

A script needs the execute permission before you can run it directly. Add it with chmod +x, then run the script by its path. The ./ tells the shell to use the file in the current folder, not a system program with the same name.

chmod +x ~/scripts/backup-site.sh
~/scripts/backup-site.sh
Backup written to /home/alex/backups/site-2026-10-31-0930.tar.gz

Check the archive is there and contains your file:

ls -lh ~/backups
tar -tzf ~/backups/site-*.tar.gz

Step 4: Read the exit code

Every command returns an exit code: 0 means success, and anything else means failure. The special variable $? holds the code of the last command. Test the error branch by pointing the script at a folder that does not exist:

mv ~/site ~/site-away
~/scripts/backup-site.sh
echo "Exit code: $?"
mv ~/site-away ~/site
Source folder /home/alex/site does not exist
Exit code: 1

Exit codes are how cron, systemd, and other tools decide whether a job worked, so always end your scripts with a meaningful code.

Tip: Run bash -n ~/scripts/backup-site.sh to check a script for syntax errors without running it. Add -x to the run command, as in bash -x script.sh, to see every command as it executes.
Careful: Never run a script you found online without reading it first. A script runs with your permissions, and it can delete or send your data.

Troubleshooting

  • "Permission denied" when you run the script. You skipped chmod +x. Run it again and retry.
  • "bad interpreter: No such file or directory" or strange characters. The file has Windows line endings. Fix them with sed -i 's/\r$//' ~/scripts/backup-site.sh.
  • "unbound variable". You used a variable that was never set, and set -u caught it. Check the spelling of the variable name.
  • "command not found". The script is running a program that is not installed, or the path to it is wrong. Use which tar to check an install.

Next steps

Once a script works by hand, you can run it automatically. Add it to your crontab with crontab -e, or wrap it in a systemd timer as shown in the uptime checks guide. Next, try adding a line that deletes backups older than 14 days, and test it with find and -print before adding -delete.

Something not working? Chat or email our support team and we will help you get unstuck.

Contact support