WolOS
Manual contents

Power user

Your first shell script

Write a shell script from nothing: what a script is, the first line, making it run, running it, a variable, a loop, and what to do when it goes wrong.

On this page

What it is

A A text file of commands that runs them in order, so a task you repeat becomes one command. is a text file with One instruction you type in a terminal, such as ls (list the files here). Return runs it. in it, one under the other. You write the commands once. From then on, one short word runs all of them, in order, the same way every time.

A shell script is written in the language you already type in the terminal. Everything What a terminal is and zsh basics taught works inside one: ls, cd, echo, paths, quotes. This page writes the scripts in bash, the shell language of most scripts you will find on the web; it reads almost the same as zsh.

You need nothing you do not already have: Text Editor to write the file, and a terminal to run it.

Why it is worth it

Anything you type more than twice is worth a script. A script does not forget a step, does not mistype a folder name at the end of a long day, and does the job the same way next month. It is also easy to share: send the file, and someone else does exactly what you did.

WolOS treats a script with care. It runs as you, with your permissions, never as the system's own account. Before you run a script you can ask WolOS to read it and point out mistakes, without running a single line.

How

1. Make a file

Open Text Editor (press Super+Space and type "text"), and type these four lines exactly:

#!/usr/bin/env bash
# My first script: says hello.
echo "Hello!"
echo "Today is $(date +%A)."

Save it in your home folder with the name hello. A script needs no ending on its name; the first line says what it is.

What each line does:

LineMeans
#!/usr/bin/env bashThe first line, called the The first line of a script, starting with #! (hash and exclamation mark). It names the program that reads the rest of the file.. It says: "read this file with bash". It must be the very first line, with nothing before #!.
# My first script: says hello.A comment. Every line that starts with # is for people; the computer skips it. Say what the script does, so you still know in a year.
echo "Hello!"Prints Hello! in the terminal.
echo "Today is $(date +%A)."$(…) runs a command and puts its answer into the text. date +%A answers with the name of the day.

2. Make it run

Open a terminal (Super+Return). Your home folder is where the terminal starts, so the file is right there. Type:

chmod +x hello

and press Return. chmod +x gives the file permission to run, the way a program has it. It prints nothing; silence means it worked. You do this once per script.

Why this step: a text file you download or write is never allowed to run on its own. You decide which files are programs. That keeps a file that only looks like a document from starting anything.

3. Run it

./hello

You see:

Hello!
Today is Wednesday.

./ means "in the folder I am in". The terminal runs only programs it knows by name, so a script of your own needs that short The address of a file: the folders you go through to reach it, separated by /. For example /home/alice/Documents/notes.txt. in front of it.

You can also run it with WolOS's own command:

wol script run hello

That works even before chmod +x. And to have the script read for mistakes without running any of it:

wol script check hello

When everything is right you see one line, hello: bash script, parses. Parses means every line made sense. With the Developer module installed, the line also says that a style checker found nothing to improve.

4. A variable

A A name that holds a value, such as a word or a number, so you can use it again further down. is a name that holds a value. Make a new file, greet:

#!/usr/bin/env bash
# Says hello to someone.
name="Alice"
echo "Hello, $name!"

name="Alice" puts the word Alice in the variable name. $name takes it out again. Run chmod +x greet, then ./greet, and you see Hello, Alice!.

A script becomes more useful when you tell it the value when you run it. Change the third line to:

name="$1"

$1 is the first Extra words after a command that tell it what to work on, such as Documents in ls Documents. you give the script. Now:

./greet Alice
./greet "Alice Liddell"

print Hello, Alice! and Hello, Alice Liddell!. The quote marks around Alice Liddell make the two words one argument.

5. A loop

A A part of a script that runs again for each item in a list, such as each photo in a folder. runs the same lines once for each item in a list. This script lists the photos in a folder of Pictures and counts them. Save it as photos:

#!/usr/bin/env bash
# Lists the photos in a folder of Pictures and counts them.
# How: ./photos Holiday
folder="$HOME/Pictures/$1"
if [ ! -d "$folder" ]; then
  echo "There is no folder called $1 in Pictures."
  exit 1
fi
count=0
for photo in "$folder"/*; do
  echo "Found: $(basename "$photo")"
  count=$((count + 1))
done
echo "$count photos in $1."

Run chmod +x photos, then ./photos Holiday:

Found: Summer Trip.jpg
Found: beach.jpg
Found: cake.JPG
3 photos in Holiday.

Read it from the top:

LinesMean
folder="$HOME/Pictures/$1"$HOME is your home folder. With Holiday, the variable holds the path of Pictures/Holiday.
if [ ! -d "$folder" ]; then … fiIf there is no such folder (! is not, -d is is a folder), say so and stop. fi closes the if.
exit 1Stops the script and reports that it failed (below).
count=0A variable to count with.
for photo in "$folder"/*; do … doneThe loop. * stands for every file in the folder; for each one, photo holds its path and the lines between do and done run.
basename "$photo"The name of the file without the folders in front of it.
count=$((count + 1))$((…)) does arithmetic: one more than before.

The name Summer Trip.jpg has a space and still comes through whole, because every variable is in double quotes.

6. Did it work? The exit status

Every command ends with an A number every command leaves behind when it ends: 0 means it worked, any other number means something went wrong.: a number, 0 when it worked, anything else when it did not. The prompt arrow turns red after a command that did not end with 0, and echo $? prints the number of the last one:

./photos Holidya
There is no folder called Holidya in Pictures.
echo $?
1

exit 1 in the script is how photos says "this did not work". Use 1 for a failure and let the script end normally when everything went well; the end of a script is a 0.

By itself, bash carries on after a command fails. To make a script stop at the first command that fails, put this line right under the first one:

set -e

A worked example

Alice wants a copy of her Documents folder every Friday, kept in a folder named after the day. She writes backup:

#!/usr/bin/env bash
# Copies Documents into a folder in Backups named after today.
# How: ./backup
set -e
today=$(date +%Y-%m-%d)
mkdir -p "$HOME/Backups/$today"
cp -r "$HOME/Documents" "$HOME/Backups/$today/"
echo "Saved a copy in Backups/$today."

date +%Y-%m-%d answers with the date as 2026-11-04. mkdir -p makes the folder, and the folders above it if they are missing. cp -r copies a folder with everything in it. set -e makes sure the last line is printed only when the copy really happened.

She runs wol script check backup (it says backup: bash script, parses), then chmod +x backup and ./backup, and sees Saved a copy in Backups/2026-11-04. In Files, Backups now holds a folder for today with Documents inside. Every Friday she presses Super+Return, types ./backup and presses Return.

If something goes wrong

The terminal tells you in one line what it did not like. The line often starts with the script's name and the number of the line in the file.

What you seeWhat it means and what to do
zsh: permission denied: ./helloThe file may not run yet. Type chmod +x hello once, then run it again.
zsh: command not found: helloYou left out ./ in front of the name. Type ./hello.
zsh: no such file or directory: ./helloNo file has that name in the folder you are in. ls shows what is there; capitals matter.
line 2: name: command not foundSpaces around =. Write name="Alice", with no spaces.
line 3: ech: command not foundA mistyped command on that line. Fix the spelling, save, and run it again. Without set -e the script carries on after this.
unexpected EOF while looking for matching and a quote markA quote mark is opened and never closed. wol script check names the line; count the quote marks on it.
Hello, !The script needs an argument and got none. Add it after the name: ./greet Alice.
Found: * and 1 photosThe folder is empty or its name is wrong, so * matched nothing. The check at the top of photos catches a wrong name.
/usr/bin/env: 'bash\r': No such file or directoryThe file was saved on Windows, with line endings bash does not read. Open it in Text Editor and save it again.
The script runs for everPress Ctrl+C to stop it, then look at the loop: something in it never ends.

The next step is Your first Ruby script: the same ladder, with a language that keeps a name with a space in it whole without any quote marks. Scripts and shells shows how to run a script on another computer.