What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
A Unix shell script is a text file of commands that a shell reads and runs. It lets you combine ordinary utilities into a repeatable task—for example, creating a directory and placing selected files inside it. To write reliable scripts, start by understanding how the shell parses text, then add quoted arguments, variables, tests, loops, and functions. This guide uses Bash for its examples; portability notes explain what to check if your script must run under POSIX sh.
What a shell does—and what a script is
The GNU Project’s Bash Reference Manual describes a Unix shell as both a command interpreter and a programming language. At the prompt, it interprets commands you enter; in a script, it reads commands from a file. Either way, the shell can run programs and connect them to other programs, while its language adds variables, decisions, repetition, and functions.
The examples below target Bash. The manual-specific behavior discussed here is documented in the GNU Bash Reference Manual, Edition 5.3, updated May 18, 2025. Other shells can differ, so do not assume every Bash example works unchanged in every Unix-like environment.
How to create and run a script
A script is plain text, not a compiled program. Its first line can name the interpreter; this line is called the shebang.
#1 Best Overall
- Create a file named
hello.shwith these lines:#!/usr/bin/env bash printf 'Hello, %sn' "$USER" - Run it explicitly with Bash:
bash hello.sh. This does not require the file to be executable. - Alternatively, make it executable and run it by path:
chmod +x hello.sh ./hello.sh
#!/usr/bin/env bash asks the environment to find Bash through PATH. If Bash is unavailable or not on that path, execution fails; use an interpreter available on the target system. Running ./hello.sh also requires execute permission and a path to the file, such as ./ for the current directory.
Commands, arguments, and the shell’s parsing order
Consider printf '%sn' 'two words'. The shell treats this as a command name followed by arguments. In broad terms, Bash reads input, recognizes words and operators according to quoting rules, parses the command, performs expansions, applies redirections, executes it, and makes the resulting exit status available. This is why shell text is not simply passed unchanged to a program.
- Unquoted spaces separate words:
one twois ordinarily two arguments. - Unquoted wildcard characters such as
*can expand to matching filenames before the command runs. - Operators such as
|and>have shell meaning when unquoted.
When exact argument boundaries matter, quote expansions and text deliberately rather than relying on how a command happens to handle spaces.
Quoting: keep text from becoming syntax
Quoting suppresses some of the special meanings the shell assigns to characters. Bash’s quoting rules distinguish single quotes, double quotes, and backslashes.
Single quotes preserve literal text
Everything between single quotes is treated literally, including dollar signs and wildcard characters. A single quote cannot appear inside a single-quoted string by simply placing a backslash before it.
printf '%sn' 'Price: $5; *.txt stays literal'
Double quotes preserve argument boundaries but allow selected expansions
Inside double quotes, Bash still expands parameters such as $name and command substitutions such as $(date), while preserving the result as one argument. For example:
name='Ada Lovelace'
printf 'Hello, %sn' "$name"
Use "$name" rather than $name in ordinary command arguments. Without quotes, spaces in the value can split it into several words, and wildcard characters may be expanded against filenames.
Rank #2
- Used Book in Good Condition
Use command substitution for a command’s output
$(...) runs a command and substitutes its output. Quoting the substitution prevents its output from being split or treated as a filename pattern:
today="$(date +%F)"
printf 'Date: %sn' "$today"
Command substitution removes trailing newline characters from the captured output. Avoid using it when the exact output, including trailing newlines, must be preserved.
Variables and script parameters
Assign a value with no spaces around the equals sign, then expand it with a dollar sign. In Bash, a variable assignment by itself does not print anything.
output_dir="$HOME/reports"
printf 'Reports will go in %sn' "$output_dir"
Shell variables are not declared with a type in this example. Quote variable expansions when using them as arguments so the value stays one argument even if it contains spaces.
Read arguments passed to the script
Positional parameters let a script use its command-line arguments: $1 is the first, $2 the second, and $# the number of arguments. Use "$@" when forwarding all arguments while preserving each argument as a separate item.
#!/usr/bin/env bash
if [ "$#" -ne 1 ]; then
printf 'Usage: %s DIRECTORYn' "$0" >&2
exit 2
fi
printf 'Requested directory: %sn' "$1"
$0 is the name or path used to invoke the script. In the example, the script checks that exactly one argument was supplied before using it.
Exit status: detect success and failure
Commands return an exit status: conventionally, 0 means success and a nonzero value indicates some kind of failure. The shell stores the most recent command’s status in $?, but another command overwrites it, so check it immediately if you need to inspect it directly.
Rank #3
cp -- "$source_file" "$destination"
status=$?
if [ "$status" -eq 0 ]; then
printf 'Copy completedn'
else
printf 'Copy failed with status %sn' "$status" >&2
exit "$status"
fi
Often it is clearer to put a command directly in an if statement, which tests its status:
if cp -- "$source_file" "$destination"; then
printf 'Copy completedn'
else
printf 'Copy failedn' >&2
exit 1
fi
The -- option ends option parsing for utilities that support it, which helps when a filename begins with a hyphen. Utility options are not universal, so check the specific command’s documentation when writing for multiple systems.
Recommended Free Tools
Conditionals: choose what to do
An if statement runs commands based on whether a test or other command succeeds. The bracket form below, [ ... ], is a command; leave spaces around its brackets.
if [ -f "$1" ]; then
printf 'Regular file exists: %sn' "$1"
else
printf 'Not a regular file: %sn' "$1" >&2
exit 1
fi
Here -f tests whether the path names a regular file. Common file checks include -d for a directory and -e for an existing path in Bash. String and numeric tests are also available; use the test expression appropriate to the value rather than comparing everything as text.
Loops: repeat a task safely
A for loop can process a list of arguments. In Bash, "$@" expands to the script’s arguments as separate items, including arguments containing spaces.
for item in "$@"; do
printf 'Item: %sn' "$item"
done
To loop over files matching a pattern, quote the pattern only if you want it treated literally. This Bash example processes matching text files in the current directory:
Free tools Windows power users keep installed
One-click scans. No signup required.
for file in ./*.txt; do
[ -e "$file" ] || continue
printf 'Found: %sn' "$file"
done
If there are no matches, Bash ordinarily leaves an unmatched pattern unchanged. The [ -e "$file" ] || continue check skips that literal pattern. Bash options can change wildcard behavior, so a script that changes shell options should do so intentionally.
Rank #4
A while loop repeats while its test command succeeds. For example, this reads lines from a file without splitting each line into separate words:
while IFS= read -r line; do
printf '%sn' "$line"
done < input.txt
IFS= prevents trimming leading and trailing whitespace during the read, and -r prevents backslashes from being treated as escapes.
Functions: name a reusable group of commands
Functions help organize repeated work. In Bash, define one with this syntax:
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchlog() {
printf '[%s] %sn' "$(date +%H:%M:%S)" "$*"
}
log 'Starting task'
Function arguments are available through positional parameters just as they are in a script. For messages where preserving argument boundaries matters, use "$@" rather than "$*". The example uses $* because it formats the arguments as one message string.
Redirection and pipelines: connect commands
Redirection changes where a command reads input or sends output. These operators are interpreted by the shell:
command > output.txtsends standard output to a file, replacing its previous contents.command >> output.txtappends standard output.command < input.txtreads standard input from a file.command 2> errors.txtsends standard error to a file.
A pipeline, written with |, connects one command’s standard output to the next command’s standard input:
grep 'ERROR' application.log | wc -l
By default, a pipeline’s status in Bash is the status of its last command, so a failure earlier in the pipeline may not be reflected. Bash’s set -o pipefail makes a pipeline return a failing status if a command in it fails; that option is Bash-specific, not portable POSIX sh syntax.
Best Value
Make a small script more reliable
This Bash example combines arguments, validation, quoting, a loop, and error handling to list regular files supplied on the command line. It prints a message for invalid input and exits with a nonzero status.
#!/usr/bin/env bash
if [ "$#" -lt 1 ]; then
printf 'Usage: %s FILE...n' "$0" >&2
exit 2
fi
for file in "$@"; do
if [ -f "$file" ]; then
printf '%sn' "$file"
else
printf 'Not a regular file: %sn' "$file" >&2
exit 1
fi
done
It expects at least one argument and stops at the first path that is not a regular file. If the desired behavior is to report every invalid path rather than stop, track failures and exit after the loop instead.
Portability: choose the shell your script needs
“Unix shell” does not name one identical language implementation. POSIX specifies important shell behavior, including flow control, program execution, input/output redirection, pipelines, argument handling, variable expansion, and quoting. Bash aims to implement the POSIX Shell and Tools portion, but its ordinary default behavior differs from POSIX in some areas. Bash also provides additional features.
For a script intended for Bash, use a Bash shebang such as #!/usr/bin/env bash and label Bash-only constructs. For a script intended to run with a POSIX shell, use a suitable sh shebang and avoid Bash-specific syntax. A script’s shebang identifies its intended interpreter; it does not make incompatible syntax portable. Bash’s POSIX mode changes some behavior to follow the standard more closely, but it is not a substitute for checking which shell features the script uses.
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 →Troubleshoot common beginner errors
- “Permission denied” when running
./script.sh: the file may not be executable. Runchmod +x script.sh, or invoke it asbash script.sh. - “Command not found” or the wrong interpreter: check the shebang and whether the named shell or command is installed and available through
PATH. - A filename with spaces becomes several arguments: quote variable expansions and arguments, such as
"$file". - A wildcard unexpectedly matches files: quote it to pass the literal characters, as in
'*.txt', or use an appropriate escaped form. - A test reports a syntax error: in the
[ ... ]form, put spaces after[and before], and quote variable expansions. - A script works in Bash but not when run with
sh: it may use Bash-specific syntax. Run it with Bash or rewrite it using constructs specified for the target POSIX shell. - A pipeline appears successful despite an earlier failure: Bash normally uses the last command’s status for the pipeline. Consider
set -o pipefailwhen the script targets Bash.
Or skip the browser setup
If your task is to capture a web page from a script, ScreenshotNeo provides a screenshot API and MCP server. A single GET request can return an image or PDF; see the ScreenshotNeo API documentation for parameters.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Its MCP server lets AI agents use screenshot tools, and the Free plan includes 1,000 screenshots per month with no card required; paid plans start at $5 for 3,000 screenshots.
Sign up for ScreenshotNeo free: 1,000 screenshots a month, no card.
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.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →




