WolOS
Manual contents

Power user

Your first Ruby script

Write a script in rsh, Ruby with terminal commands in it: a file ending in .rsh, Ruby and commands on the same page, why each value stays one argument, catching a command that failed, and running it with ./ and with wol script.

On this page

What it is

Ruby with commands in it: one script can hold Ruby and terminal commands side by side. It comes with WolOS. is A programming language known for reading almost like English. WolOS runs Ruby scripts the same way as shell scripts. with terminal One instruction you type in a terminal, such as ls (list the files here). Return runs it. in it. A script in rsh is a Ruby program, and any line that starts with a word Ruby does not know is run as a command, exactly as you would type it in the terminal. So one file holds both: Ruby to count, decide and repeat, and commands such as ls, mkdir and cp to do the work.

rsh comes with WolOS. Its scripts end in .rsh. If you have read Your first shell script, this page climbs the same ladder: a file, the first line, making it run, running it, then values, a loop and what to do when something fails.

Why WolOS does it this way

A shell script is quick to write and easy to get wrong. Every value is text that the shell splits again at each space, so a file called Summer Trip.jpg turns into two files that do not exist unless you remember the quote marks every time. A command that fails is easy to miss, and the script carries on.

Ruby has none of those traps, but in plain Ruby running a command takes a whole line of code. rsh keeps both: you write commands the way you type them, and they get Ruby's care. A value you put into a command is always exactly one Extra words after a command that tell it what to work on, such as Documents in ls Documents., whatever it holds. A command that fails stops the script and says where, unless you catch it and decide what to do.

How

1. Make a file

Open Text Editor (press Super+Space and type "text"), and type:

#!/usr/bin/env rsh
# My first rsh script: Ruby and commands together.
name = ENV.fetch("USER")
puts "Hello, #{name}!"
ls ~/Pictures/Holiday

Save it in your home folder as hello.rsh.

What each line does:

LineMeans
#!/usr/bin/env rshThe first line, the The first line of a script, starting with #! (hash and exclamation mark). It names the program that reads the rest of the file.: "read this file with rsh".
# My first rsh …A comment, for people.
name = ENV.fetch("USER")Ruby: puts your account name in the A name that holds a value, such as a word or a number, so you can use it again further down. name.
puts "Hello, #{name}!"Ruby: prints a line. #{…} puts a value into the text.
ls ~/Pictures/HolidayA command: Ruby has nothing called ls, so rsh runs it as in the terminal.

How rsh tells them apart is the first word of the line. Something Ruby knows (name, puts, if, end, a name starting with a capital) makes the line Ruby. A word Ruby does not know makes it a command.

2. Make it run and run it

Open a terminal (Super+Return) and type, once:

chmod +x hello.rsh

Then run it:

./hello.rsh

You see:

Hello, aliceliddell!
Summer Trip.jpg
beach.jpg
cake.JPG

The first line came from Ruby, the rest from ls.

WolOS's own command runs it too, with no chmod needed, and can read it for mistakes first without running anything:

wol script check hello.rsh
wol script run hello.rsh

The check answers hello.rsh: rsh script, parses and rsh is clean: every line made sense, and rsh found nothing risky in it.

3. Ruby uses what a command says

Put a command between back-quotes, `, and Ruby gets its answer as text. Save this as count.rsh:

#!/usr/bin/env rsh
# Counts the photos in a folder of Pictures.
# How: ./count.rsh Holiday
folder = ARGV.fetch(0)
photos = `ls ~/Pictures/#{folder}`.lines.size
puts "#{folder} holds #{photos} photos."

ARGV.fetch(0) is the first argument you give the script. .lines.size counts the lines of what ls printed. Run chmod +x count.rsh, then ./count.rsh Holiday, and you see Holiday holds 3 photos.

4. A loop, with one argument per value

This script moves the photos of a folder into a new folder, Sorted, and writes the ending .JPG in small letters on the way. Save it as sort.rsh:

#!/usr/bin/env rsh
# Moves the photos of a folder into Sorted, with .jpg in small letters.
# How: ./sort.rsh Holiday
folder = File.join(ENV.fetch("HOME"), "Pictures", ARGV.fetch(0))
mkdir -p #{folder}/Sorted
count = 0
Dir.glob("#{folder}/*.{jpg,JPG}").each do |photo|
  name = File.basename(photo).sub(/\.JPG\z/, ".jpg")
  mv #{photo} #{folder}/Sorted/#{name}
  count += 1
end
puts "Moved #{count} photos into Sorted."

Run chmod +x sort.rsh, then ./sort.rsh Holiday. You see Moved 3 photos into Sorted., and in Files, Pictures/Holiday/Sorted holds Summer Trip.jpg, beach.jpg and cake.jpg.

LinesMean
folder = File.join(…)Ruby builds the The address of a file: the folders you go through to reach it, separated by /. For example /home/alice/Documents/notes.txt. of the folder from its parts.
mkdir -p #{folder}/SortedA command, with a Ruby value inside: #{…} in a command line puts the value in.
Dir.glob(…).each do |photo| … endA A part of a script that runs again for each item in a list, such as each photo in a folder.: for every file ending in .jpg or .JPG, photo holds its path and the lines up to end run.
name = File.basename(photo).sub(…)Ruby: the file name, with .JPG at the end changed to .jpg.
mv #{photo} #{folder}/Sorted/#{name}A command: moves the file.

Summer Trip.jpg moved as one file, with no quote marks anywhere. That is the rule that keeps you safe: a value in a command is always exactly one argument. It is never split at a space, never read as a pattern, and never read as another command. Try it:

#!/usr/bin/env rsh
name = "Summer Trip; rm -rf ~"
echo #{name}

This prints Summer Trip; rm -rf ~ and does nothing else. In a careless shell script the ; would end one command and start the next, and the next one would delete your home folder. A file name from the web, from a download or from someone else's folder can hold anything; in rsh it stays a name.

5. When a command fails

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., 0 when it worked. When a command in an rsh script ends with anything else, the script stops there and tells you the file, the line and the number. Here is copy.rsh, run when there is no folder called Backup:

#!/usr/bin/env rsh
cp ~/Documents/notes.txt ~/Backup/
puts "Notes copied."
cp: cannot create regular file '/home/aliceliddell/Backup/': Not a directory
rsh: ./copy.rsh:2: cp exited 1

The first line is what cp said; the second is rsh telling you that line 2 failed, so Notes copied. was never printed. A script never carries on as if a step had worked.

To decide yourself what happens, put the command between begin and rescue. Ruby calls this rescuing a failure:

begin
  cp -r ~/Documents ~/Backups
  puts "Saved a copy."
rescue => e
  puts "The copy did not work: #{e.stderr.strip}"
  exit 1
end

If cp works, you see Saved a copy. If it fails, the lines after rescue run: e holds what went wrong, and e.stderr is what the command said about it. exit 1 ends the script and reports the failure.

A command used as a question, after if or unless, never stops the script; it is just yes or no:

if grep -q milk ~/Documents/notes.txt
  puts "Milk is on the list."
end

A worked example

Alice wants a copy of Documents in a folder named after today, and a clear sentence when something stops it. She writes backup.rsh:

#!/usr/bin/env rsh
# Copies Documents into a folder in Backups named after today.
# How: ./backup.rsh
today = Time.now.strftime("%Y-%m-%d")
target = File.join(ENV.fetch("HOME"), "Backups", today)
mkdir -p #{target}
begin
  cp -r ~/Documents #{target}
  puts "Saved a copy in Backups/#{today}."
rescue => e
  puts "The copy did not work: #{e.stderr.strip}"
  exit 1
end

Time.now.strftime("%Y-%m-%d") is Ruby for today's date, as 2026-11-04. She runs wol script check backup.rsh, which answers backup.rsh: rsh script, parses and rsh is clean, then wol script run backup.rsh, and sees Saved a copy in Backups/2026-11-04. On a computer without a Documents folder the same script says The copy did not work: cp: cannot stat '/home/aliceliddell/Documents': No such file or directory and ends with exit status 1.

If something goes wrong

What you seeWhat it means and what to do
zsh: permission denied: ./hello.rshThe file may not run yet. Type chmod +x hello.rsh once, or use wol script run hello.rsh.
rsh: ./copy.rsh:2: cp exited 1The command on line 2 failed and the script stopped. The line above it is what the command said. Fix the cause, or rescue it (step 5).
rsh: lss: command not foundA command name is misspelled, or the program is not installed.
index 0 outside of array bounds with IndexErrorThe script needs an argument and got none. Add it after the name: ./count.rsh Holiday.
a value in a command is nilA variable you put in a command holds nothing (Ruby calls that nil). rsh stops instead of running the command with a missing word. Check where the variable is set.
A line you meant as a command ran as RubyIts first word is also a variable or method in your script, such as date after date = …. Put $ in front to force a command: $ date +%A.
undefined method with NoMethodErrorA Ruby word is misspelled, or it is not in the Ruby that comes with rsh. For your home folder, write ENV.fetch("HOME").
bad.rsh:3:0: syntax error, unexpected end of filersh stopped understanding the file at line 3: usually an end or a closing quote mark is missing above it. wol script check shows this without running anything; fix the line, save, check again.

Where to learn more

The rsh page shows more of what rsh does, with each job written both as a shell script and in rsh. Scripts that change settings shows what WolOS asks before a script changes a setting, and Scripts and shells how to run a script on another computer.