What is the Rc Shell and How to Install It in Linux

Quickly get acquainted with rc shell.

Rc Shell 00 Featured Image

The rc shell is a simple and innovative command interpreter built for the Plan 9 family of operating systems. It is currently a part of plan9port, which is a suite of Plan 9 software that is available for Linux.

Rc aims to improve on the default UNIX shell and it introduces a cleaner syntax for writing scripts. It is also built to be as simple to understand as possible. This makes rc a good program for someone that wants to learn how a shell works.

What is Plan 9?

In a basic sense, Plan 9 is the successor to the UNIX operating system. It was developed by Bell Labs as an experimental project from the early 1980s up until 2015. Since then, a group of volunteers have been maintaining the operating system and it still sees occasional updates to this day.

Rc Shell 02 9legacy Website View

Plan 9 aims to produce a simple and approachable system for both developers and users alike. It does this by implementing and improving on the basic UNIX concept. As such, Plan 9 carries a lot of similar commands to UNIX and other UNIX-likes such as cp, mv and rm.

Further, it also adds a number of new utilities and features that are unique to the operating system. For example, sam is a powerful text editor that you can fully control using regular expressions.

Rc Shell 03 Sam Editor Linux

One of the most innovative features of Plan 9 is the rc shell. It is a command interpreter similar to Bash and it allows you to create scripts which you can then use to automate your machine. rc also aims to simplify how you create these scripts by removing all unnecessary and redundant features.

Rc Shell 04 Rc Manpage 1

Installing the Rc Shell

Installing the rc shell in Linux is relatively straightforward.

  1. Copy the Git repository of the Plan 9 tools to your machine. You can do that by installing Git and running the following commands:
git clone https://github.com/9fans/plan9port.git /home/$USER/plan9port
cd plan9port
  1. Next up, run the installation script that comes with the repository. This is a simple script that compiles a Plan 9 builder which, in turn, compiles the rest of the utilities. To do this, you need to run the following:
./INSTALL
Rc Shell 05 Compiling Plan9port
  1. Once done, you can now use the Plan 9 utilities by going to the repository’s bin directory. For example, we’ll type ./bin/acme to run a graphical text editor.
Rc Shell 06 Acme Editor
  1. One important thing to note is that these commands will only work while you are in plan9port’s “bin” directory. In order to use these elsewhere, you need to add this particular directory to your “PATH” variable. To do that, you need to open the “.bash_profile” file in your home directory:
nano /home/$USER/.bash_profile
  1. Add the following string of text at the end of your “PATH” variable:
:/home/$USER/plan9port/bin/
Rc Shell 07 Editing Path Variable

Save and exit the file, and restart the rc shell.

Using and Writing Basic Rc Scripts

With that done, you can now start scripting in rc. In order to access this shell, all you need to do is to run the following command:

9 rc

Doing that will change the prompt of your terminal to “%”. This indicates that you are now inside the rc shell. From here, you can still access all of your files as well as traditional Linux commands. For example, we’ll type ls to get a list of the current directory.

Rc Shell 08 Ls Inside Rc

Variables and File Operators

One of the most common uses for a shell language is for storing arbitrary values as well as manipulating files. In this regard, rc shell behaves exactly like Bash.

  1. We’ll write the following to create a variable with the name “test” and assign the word “hello” to it:
test=hello
  1. From there, we’ll type the following command to append the test variable to the file “world.txt”:
echo $test >> world.txt
  1. On the other hand, it’s possible to also instruct the read operator to use the contents of a file as an input for a program:
cat < world.txt
Rc Shell 09 Variables And Printing

Using UNIX Pipes in Rc Shell

Another common function in shell languages is the ability to create UNIX pipes. This is a special type of file operator where you can pass the output of one program to a different program’s input.

Similar to the functions above, rc shell largely follows the traditional Bash syntax when creating UNIX pipes.

  1. We’ll run the following command to pass the contents of the “world.txt” file to a system pager:
cat world.txt | less
  1. We should note here that UNIX pipes in rc are non-linear. This means that it is possible to pass the output from two active programs in a single program’s input. For example, we can run the following command to compare the output of two programs:
cmp <{echo hello} <{echo helloo}
Rc Shell 10 Branching Pipes

Chaining Commands in Rc Shell

Aside from using UNIX pipes, it is also possible to chain different commands in rc shell. This allows you to run programs in sequence without the need to type them in separate lines. Check out this command that allows you to run less after running echo:

echo hello-world >> hello.txt; less hello.txt

Further, rc also allows you to check a program’s status code before going to an adjacent command. This can be useful if your program depends on either the success or failure of other programs.

To this end, rc provides two operators: &&” and ||. These are special characters which you can use to replace the semicolon symbol.

  • The && operator tells rc to chain and run programs as long as the command on the left side runs successfully. This is helpful in situations where you need the whole chain to run properly.
  • The || operator tells rc to chain and run programs if the command on the left side fails to run. Unlike the previous operator, this is incredibly useful if you are trying to fix issues in your scripts and programs.

Knowing that, you can then use these operators to create commands that can queue and check programs. For example, we’ll instruct rc to only run touch if mkdir runs successfully:

mkdir ./hello && touch ./hello/world
Rc Shell 11 Chained Commands

Using Strings and Lists in Rc Shell

One of the biggest differences between Bash and the rc shell is the latter’s focus on simplifying the use of plain text. In traditional shell, text and strings are often hard to declare in functions and variables.

This issue is partly due to the fact that there are two ways to declare a string in Bash. It is possible to enclose text in both single and double quotes to treat a word as a string.

Rc Shell 12 Multiple String Quotes

As such, rc aims to reduce this complexity by only using single quotes when declaring strings. Doing this allows you to use special and control characters without any issues.

By using this command we’ll turn a bracket to a string without any escape characters:

# rc
hello='[world]'
# bash
hello='\[world\]'

Further, rc also allows you to manipulate these string variables and directly compile them as a list. This can be especially useful if you want to create a script that stores variables in a simple array.

To do this, all you need to do is to enclose a group of strings in parenthesis. As such, we’ll write the following to create a variable with 5 elements inside it:

shop=(eggs milk cheese rice beef)

Knowing that, you can then use a variety of commands to pull data out of an array. For example, this command will pull the first three elements of an array:

echo $shop(1 2 3)
Rc Shell 13 Basic Lists

Basic Flow Control in Rc Shell

Aside from being a simple shell, rc is also a full programming language. This means that it is capable of not only basic string manipulation but also of logical branching similar to Python.

Rc Shell 14 Example Complex Code

Rc allows you to easily create if-then statements, for loops as well as the ability to define complex functions. This can be incredibly helpful if you are just starting out with programming.

Using Conditional Statements

One of the most basic feature of programming languages is the ability to create conditional statements. These are structures which tell a program what to do depending on the circumstance that it is in. For example, you can tell a program to only run if it has a value of 1.

Rc Shell 15 Basic Conditional Statement View

You can write a conditional statement for rc in a single line:

if ( condition ) program
  • The “condition” field is a list of commands that rc will attempt to run. The way it works is that any program that successfully runs itself provides a value of “true”.
  • The “program” field, on the other hand, depends on the condition field’s “true” value to run any command that you give to it.

Unlike Bash, this approach allows you to use almost any type of program for a script’s conditional statement. For example, you can tell rc to only run this statement if a hello.world file exists in the current directory:

if ( test -r hello.world ) echo "there is a hello world!"

Creating Simple for Loops

Aside from writing conditional statements, it is also possible to use rc for creating repeating scripts through loops. A loop is a structure that allows you to repeat a particular command for set number of times.

Rc Shell 15 Basic Conditional Statement View

Similar to conditional statements, you can also write the syntax of a loop in a single line:

for ( i in step ) program
  • The “step” field can either be a variable or a program that rc will go through one by one. For example, writing a list here will tell rc to go through each element of the list.
  • The “program” field is the line of code that you want rc to run every time it goes through the step field.

Creating Functions in Rc

Lastly, it is also possible to create a general function in rc. Similar to other programming languages, this is a structure that you can define to perform a custom task.

Rc Shell 17 Basic Function Code

For example, the following will create a function that uses both conditional statements and for loops:

fn hello {
    for (i in ./hello/) if(test -r ./hello/$i) echo "There is a file here!"
}

While this might seem complex, writing a function is incredibly simple. At its core, the basic syntax of an rc function looks something like this:

fn name { function }
  • The “name” field tells rc the label of a particular function. This can be especially useful if you want to reuse the same function for a later command.
  • The “function” field, on the other hand, contains all the variables and commands that you want it to run.

Frequently Asked Questions

Is it possible to know the number of elements in a list in Rc?

Yes! It is possible to check the total amount of variables in an rc list. Similar to obtaining list elements, you can do this by adding a double quote (“) symbol before your list’s name. For example, we can type echo $"shop to print the total number of elements that we stored in the shop variable.

Is it possible to create infinite loops in Rc?

Yes! It is possible to create loops in rc shell that do not end. While the examples above show finite loops, creating infinite ones are also just as simple. To do this, you only need to remove any condition in the step field. One important thing to note, however, is that you still need to place a parenthesis in the step field for an infinite loop. This is because the rc shell is designed to only recognize functions with a particular syntax and structure. For instance, the command for(i) echo hello will tell rc to print the word “hello” indefinitely.

Is it possible to pass errors in Rc similar to >2 in Bash?

Yes! By default, rc provides a way to separate any diagnostic output from a program. This can be useful if you are trying to fix an issue with a script or program that you are running. With this in mind, you can separate this type of output by using the “>[2=1]” file operator. For example, we can print any errors in our script by running the following command: ./script.rc >[2=1] ./error.log.

Image credits: Unsplash All screenshots by Ramces Red

Subscribe to our newsletter!

Our latest tutorials delivered straight to your inbox