A shell script is a plain-text file containing commands that Bash executes. On a Linux VPS, you can create one over SSH, test it with bash script.sh, restrict it with chmod 700, run it directly with a valid shebang, and schedule it with cron. This guide walks through that process and explains the permission, environment, and reliability details that commonly cause failures.
Need a server to try this on? Antihost offers Linux VPS plans with NVMe storage, full root access and a 14-day free trial.
What a shell script is on a Linux VPS
GNU Bash defines a shell script as “a text file containing shell commands.” Bash reads those commands and executes them in a non-interactive shell. The file can contain one command or a complete repeatable workflow: writing a log entry, rotating files, checking a service, or running maintenance commands.
As an Amazon Associate I earn from qualifying purchases.
A script is not a special binary format. It is text interpreted by a shell. The first line normally selects the interpreter, and the remaining lines are commands, variables, tests, loops, or functions understood by that interpreter. This distinction matters because a script written for Bash may not behave the same way when run by a smaller POSIX shell.
For Bash scripts, the portable shebang is usually #!/usr/bin/env bash. It asks the system to find bash through the configured environment. #!/bin/bash is also valid when Bash is guaranteed to exist at that exact path. Bash documents the #! mechanism and these common forms in its Shell Scripts reference.
#1 Best Overall
- Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
- Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
- Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
- Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
- 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
Before you start: connect to the VPS
You need an account that can log in through SSH and permission to create files in its home directory. Use your VPS address and account name in the SSH command:
ssh user@your-vps
After authentication, commands run on the VPS rather than on your local computer. Confirm the account and host if you manage several servers:
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →whoami
hostname
pwd
The examples below keep the script in ~/bin. A personal bin directory keeps small utilities together without requiring administrator access:
mkdir -p ~/bin
If the directory is new, your shell may not include it in PATH. That does not prevent you from running a script by its full path, such as ~/bin/hello-vps.sh.
Create your first Bash script
Open a file in the terminal
Use a terminal editor such as nano:
nano ~/bin/hello-vps.sh
Enter this complete example:
#!/usr/bin/env bash
printf 'Hello from %sn' "$HOSTNAME"
printf 'Running as %sn' "$USER"
The blank line is optional, but separating the interpreter line from the commands makes the file easier to scan. printf receives a format string and values explicitly, so the output is predictable. The variables are quoted; that practice prevents word splitting and unexpected behavior if a value contains spaces or is empty.
Save and exit nano
- Press
Ctrl+Oto write the file. - Press
Enterto confirm the filename. - Press
Ctrl+Xto leave the editor.
At this point the file is text. It does not need execute permission to be interpreted explicitly by Bash.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Test a script with Bash before changing permissions
Run the file by passing it to Bash:
bash ~/bin/hello-vps.sh
You should see two lines identifying the host and the account running the script. This form does not rely on the file’s execute bit, and Bash is selected by the command you typed. It is useful for an initial test or for diagnosing a shebang or permission problem.
You can also check the file’s contents and metadata:
sed -n '1,10p' ~/bin/hello-vps.sh
ls -l ~/bin/hello-vps.sh
If Bash reports a syntax error, fix the indicated line and run the same test again. Test a script after each meaningful change instead of waiting until it is used by an automated job.
Rank #2
- 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
- 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
- Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
- 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
- What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.
Make the script executable without exposing it to other users
To launch a file directly, the file must have execute permission and a usable shebang. For a personal administrative script, give the owner read, write, and execute access while excluding everyone else:
Free tools Windows power users keep installed
One-click scans. No signup required.
chmod 700 ~/bin/hello-vps.sh
Mode 700 means:
- Owner: read, write, and execute.
- Group: no permissions.
- Others: no permissions.
The Linux Foundation documents this owner-only pattern in Writing a Simple Bash Script. Do not automatically use 700 for every script: choose a narrower mode when the task does not require one of those permissions, and choose a deliberately shared mode only when another account must run the file.
Inspect the result:
ls -l ~/bin/hello-vps.sh
A typical listing begins with -rwx------. The exact owner and date will differ on your VPS.
Run the script directly
Use its path from any working directory:
~/bin/hello-vps.sh
If you are already in the directory, use:
cd ~/bin
./hello-vps.sh
The ./ prefix means “the file named hello-vps.sh in the current directory.” Linux generally does not search the current directory automatically, so typing only hello-vps.sh may produce “command not found” unless that directory has been added to PATH.
These are the two normal execution forms:
| Command | What selects Bash | Required file permissions | When to use it |
|---|---|---|---|
bash script.sh |
The command explicitly invokes Bash | Read permission for the invoking account | Initial tests or scripts that are not executable |
./script.sh or an absolute path |
The shebang in the first line | Read and execute permission, plus a valid shebang | Manual use, cron, and other tools that launch the file |
GNU’s Bash Reference Manual, updated May 18, 2025, describes both the script format and the execute-bit behavior.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesFix the most common execution errors
“Permission denied”
Check the mode and the directory permissions:
ls -l ~/bin/hello-vps.sh
ls -ld ~/bin
If the file lacks the owner execute bit, run chmod 700 ~/bin/hello-vps.sh as the file owner or an account authorized to change it. If you only need to test the contents, bypass the execute bit with bash ~/bin/hello-vps.sh. A directory also needs execute permission for a user to access files inside it.
“No such file or directory” with a correct-looking filename
Verify the current directory and use an absolute path:
pwd
ls -l
~/bin/hello-vps.sh
A relative path is interpreted from the current working directory. A typo in capitalization also matters on the usual case-sensitive Linux filesystems.
“Command not found” after typing the filename
Use ./hello-vps.sh from its directory or the full path ~/bin/hello-vps.sh. Adding a personal directory to an interactive PATH does not automatically make it available to cron or systemd.
Rank #3
- Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
- Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
- Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
- Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
- What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.
“Bad interpreter” or an invisible ^M
Windows-style carriage-return line endings can make the shebang point to a path that does not really exist. Inspect the file type:
file ~/bin/hello-vps.sh
If it reports CRLF or Windows line endings, resave or convert the file with Unix line endings, then check the first line again. The first two characters must be #!, with no blank line or hidden character before them.
The script works over SSH but fails when automated
Interactive SSH sessions often load a different PATH and different variables from cron or a systemd timer. Use absolute paths for important commands, define the required PATH explicitly, and write errors to a log. Never assume that aliases, shell startup files, or your interactive working directory exist in a scheduled job.
Write scripts that behave predictably
Quote variable expansions
Quote values such as "$HOME" and "$1" whenever they represent a path or user-supplied text:
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →#!/usr/bin/env bash
printf 'Home directory: %sn' "$HOME"
printf 'First argument: %sn' "${1:-not supplied}"
Without quotes, spaces can split one intended value into several words, and an empty value can disappear from a command. The ${1:-not supplied} form supplies readable output when no first argument was given.
Prefer printf when output matters
printf makes newlines and substitutions explicit. That is preferable to relying on ad-hoc formatting, especially when output is redirected to a log or consumed by another command.
Check commands that can leave partial state
A script that creates files, changes permissions, restarts a service, or removes data should not silently continue after a critical failure. Use explicit checks:
Recommended Free Tools
if mkdir -p "$HOME/logs"; then
printf 'Log directory is readyn'
else
printf 'Could not create the log directoryn' >&2
exit 1
fi
You can also adopt an intentional Bash error policy, such as set -euo pipefail, but understand its effects before applying it to existing code. Conditions, pipelines, commands expected to return nonzero, and cleanup logic need to be written with that policy in mind. A blanket option is not a substitute for deciding which failures are safe to ignore.
Use arguments instead of editing repeated values
For a reusable script, accept a path or other input as an argument and validate it before use. Keep the quoting around the argument:
Rank #4
- Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
- Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
- Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
- Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
- Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
target="${1:-$HOME}"
printf 'Target: %sn' "$target"
For destructive operations, add a clear check and require an explicit value rather than defaulting to a broad location.
Keep VPS scripts secure
- Store administrative scripts in a protected directory. A directory writable by an untrusted user could allow that user to replace a script before a privileged process runs it.
- Avoid unnecessary
sudo. Run the script as the account that owns the files it needs whenever possible. If one operation truly needs elevated rights, isolate and review that operation. - Never use SUID or SGID shell scripts. Shell parsing, environment handling, and the many commands a script can invoke make this arrangement extremely difficult to secure sufficiently. Google’s Shell Style Guide warns against it.
- Do not embed passwords or private keys. Read secrets from a protected file or a secret-management facility, with permissions appropriate to the account that runs the script.
- Review every variable that reaches a command. Quoting prevents accidental word splitting, but it does not make arbitrary input safe for every command. Validate paths and allowed values where the script performs privileged or destructive work.
- Restrict logs when they contain sensitive data. Redirect output deliberately and make sure the log directory is not broadly writable.
Owner-only mode is a useful baseline, not a complete security model. The account’s SSH access, directory ownership, command choices, and any scheduler permissions matter as well.
Schedule a script with cron
Prepare a log directory
Before scheduling, create the destination for output:
mkdir -p ~/logs
Run the exact command manually first. For the example script:
/home/USER/bin/hello-vps.sh >> /home/USER/logs/hello-vps.log 2>&1
Replace USER with the actual account name. Using absolute paths here avoids depending on cron’s working directory or PATH.
Install a user crontab entry
Open the crontab belonging to the account that should run the job:
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallcrontab -e
Add this line to run the script every day at 03:15 according to the VPS’s cron timezone:
15 3 * * * /home/USER/bin/hello-vps.sh >> /home/USER/logs/hello-vps.log 2>&1
The five time fields are minute, hour, day of month, month, and day of week. The final command redirects standard output to the log in append mode; 2>&1 sends standard error to the same destination. Keeping both streams makes failures visible when nobody is watching an SSH session.
Understand cron’s restricted environment
Cron is non-interactive. It may not load the same shell startup files, aliases, variables, or PATH as an SSH login. A robust scheduled script should:
Best Value
- 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
- Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
- Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
- HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
- What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.
- Use an absolute path to the script and to important external commands.
- Set any required environment variables near the top of the script.
- Use absolute paths for input, output, and temporary locations.
- Write useful failures to a log or another monitored destination.
- Be safe to run repeatedly if a previous run is retried manually.
The VPS.DO Linux scripting guide also highlights the difference between interactive and automated environments.
Protect the crontab
The crontab(5) manual states that crontab files must not be executable or writable by anyone else. Use crontab -e rather than editing a system crontab file by hand, and do not place a shared writable file in a location where a different account can alter the commands that will run.
When a systemd timer is a better fit
Cron is a straightforward choice for a simple daily or hourly command. A systemd service plus timer is often easier to operate when you need dependencies, retries, structured status, or centralized journal logs. The right choice depends on the job rather than on the file extension.
| Concern | Cron | systemd timer |
|---|---|---|
| Trigger semantics | Compact calendar fields such as “15 3 * * *” | Timer units express calendar or elapsed-time triggers and can be paired with service units |
| Environment | Minimal, non-interactive environment; paths must be explicit | Unit files make the command, user, working directory, and environment more explicit |
| Logging | Usually explicit redirection to a file or mail configuration | Can integrate with the system journal and service status |
| Permissions | User crontabs run as their owner; system entries require careful ownership | The service unit declares the account and security settings |
| Failure visibility | Depends on captured output and monitoring | Service state and exit status are visible through systemd tools |
| Manual re-run | Run the command copied from the crontab | Start the service unit directly and inspect its status and journal |
For a one-line personal maintenance task, cron has less configuration. For a long-running or operationally important workflow, the additional structure of systemd can make failures and dependencies clearer. Whichever scheduler you use, test the command manually under the same account and with the same absolute paths.
A practical script pattern for a VPS
The following example adds an argument, a predictable log directory, and explicit failure handling while remaining small enough to understand:
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →#!/usr/bin/env bash
log_dir="$HOME/logs"
message="${1:-manual run}"
if ! mkdir -p "$log_dir"; then
printf 'Cannot create %sn' "$log_dir" >&2
exit 1
fi
printf '%s: %s on %sn' "$(date '+%Y-%m-%d %H:%M:%S')" "$message" "$HOSTNAME"
>> "$log_dir/hello-vps.log"
Save it, test it explicitly, then make it executable:
bash ~/bin/hello-vps.sh "first test"
chmod 700 ~/bin/hello-vps.sh
~/bin/hello-vps.sh "direct test"
tail -n 5 ~/logs/hello-vps.log
This pattern demonstrates several operational habits: the script creates only the directory it owns, quotes expansions, appends to a known file, and returns a nonzero status if setup fails. It is still your responsibility to decide whether the account has permission to write the selected location and whether the logged message contains anything sensitive.
A repeatable workflow for every new script
- Define the job. Write down the input, output, account, and acceptable failure behavior before adding commands.
- Create the file in a protected directory. Use
mkdir -p ~/binand an owner-controlled editor. - Put the shebang first. Use
#!/usr/bin/env bashunless the server’s Bash path is intentionally fixed. - Quote expansions and use explicit paths. This matters most for filenames, arguments, logs, and scheduled execution.
- Run it with Bash. Start with
bash /full/path/script.shso content errors are separated from execute-bit errors. - Check failure paths. Decide what should happen if a command cannot create, copy, connect, or restart something.
- Set the minimum practical permissions. Use
chmod 700for an owner-only executable when that is the intended access model. - Run it directly. Confirm that the shebang and execute permission work with the full path.
- Schedule only after manual success. Copy the exact tested command into
crontab -eand redirect both output streams. - Inspect logs after the first scheduled run. A successful installation of a cron entry does not prove that the command completed successfully.
Useful inspection commands
| Goal | Command |
|---|---|
| Show the current account | whoami |
| Show the VPS hostname | hostname |
| Show the working directory | pwd |
| List file permissions | ls -l /full/path/script.sh |
| List directory permissions | ls -ld /full/path |
| Display the first lines | sed -n '1,10p' /full/path/script.sh |
| Identify line-ending or file-type problems | file /full/path/script.sh |
| Show the installed user crontab | crontab -l |
| Read recent log output | tail -n 20 /full/path/logfile.log |
These checks are intentionally simple. They establish which account, path, permissions, and file format are actually involved instead of relying on assumptions from an interactive terminal.
Where to go next
Once the basic workflow is comfortable, learn Bash’s quoting, tests, functions, redirections, pipelines, and exit statuses before turning a short script into a larger deployment tool. Keep scripts small, review changes before granting execute permission, and make logs useful enough to diagnose a failed unattended run. For broader Linux administration and shell-scripting study, the UNIX and Linux System Administration Handbook, 4th Edition provides a wider reference.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




