Unit 7: The Shell Is a Language
Variables, questions and loops.
Unit 7 of 8 in Linux and the command line for kids. Its 7 lessons are Remembering Things, Two Kinds of Quotes, The Answer Inside, Doing It to Everything, Asking Questions, Again and Again and Four Hundred Files — below is everything each one explains, and a question or two from it to try.
Every terminal session on this page was replayed before it shipped, on a machine whose every message is tested against real bash and coreutils.
This unit opens with a fortnight’s trial of everything — no card needed — or with a family plan, bought in the iPhone app. The first two units of every track are free for ever. Try it in the app.
📦 Remembering Things
A box with a name on it
The shell can remember things. NAME=Sam puts Sam in a box called NAME.
To get it back out you put a $ in front: $NAME. The dollar means "not the word NAME — what is *in* NAME".
Terminal
kid@alguni:~$ NAME=Sam kid@alguni:~$ echo $NAME Sam kid@alguni:~$ echo "hello, $NAME" hello, Sam
No spaces round the equals
This one catches everybody: NAME = Sam does not work.
The shell splits at spaces, so it sees three words and tries to run a program called NAME. Write it with no spaces at all: NAME=Sam.
Terminal
kid@alguni:~$ NAME = Sam bash: NAME: command not found
Boxes the shell filled in for you
Some are already there when you arrive. $HOME is your home folder, $USER is your name, and $PWD is where you are standing.
env lists the lot. These are how programs find out about you without asking.
Terminal
kid@alguni:~$ echo $HOME /home/kid kid@alguni:~$ echo $USER kid kid@alguni:~$ cd /tmp kid@alguni:/tmp$ echo $PWD /tmp
Try it yourself
What does this print?
Terminal
PET=cat
echo "I have a $PET"
Answer it in the app
💬 Two Kinds of Quotes
They are not the same
Double quotes keep spaces together but still swap $NAME for what is in it.
Single quotes keep everything exactly as typed. No dollars, no wildcards, nothing.
So double quotes are the ones you want almost always, and single quotes are for when you mean the characters themselves.
Terminal
kid@alguni:~$ NAME=Sam kid@alguni:~$ echo "hello $NAME" hello Sam kid@alguni:~$ echo 'hello $NAME' hello $NAME
The reason you always quote a variable
A filename can have a space in it. If it does, $FILE on its own falls apart — the shell splits it into two words and the command sees two files.
"$FILE" in double quotes stays one thing. This is the single most useful habit in the whole unit.
Terminal
kid@alguni:~$ FILE="my homework.txt" kid@alguni:~$ ls $FILE ls: cannot access 'my': No such file or directory ls: cannot access 'homework.txt': No such file or directory kid@alguni:~$ ls "$FILE" my homework.txt
Try it yourself
Which prints the four characters $PET?
- echo '$PET'
- echo "$PET"
- echo $PET
- echo PET
What comes out?
Terminal
WORD=fish
echo '$WORD'
Answer them in the app
🪄 The Answer Inside
Run this bit first
$(...) runs whatever is inside it and puts the answer in its place.
So echo "there are $(ls | wc -l) files" runs the pipeline first, gets back a number, and prints the sentence with the number in it.
Terminal
kid@alguni:~$ ls | wc -l 3 kid@alguni:~$ echo "there are $(ls | wc -l) files here" there are 3 files here kid@alguni:~$ COUNT=$(ls | wc -l) kid@alguni:~$ echo $COUNT 3
Sums
There is a second kind with two brackets: $(( )) does arithmetic.
It only does whole numbers, so $(( 7 / 2 )) is 3 — the shell throws the remainder away rather than rounding.
Terminal
kid@alguni:~$ echo $(( 2 + 3 )) 5 kid@alguni:~$ echo $(( 7 / 2 )) 3 kid@alguni:~$ N=4 kid@alguni:~$ echo $(( N * N )) 16
Try it yourself
What does this print?
Terminal
echo $(( 10 - 3 * 2 ))
Answer it in the app
🔁 Doing It to Everything
The loop
This is what a terminal is *for*.
for takes a list, puts each thing into a box in turn, and runs the same commands on it. Everything between do and done happens once per item.
Terminal
kid@alguni:~$ for colour in red green blue; do echo "I like $colour"; done I like red I like green I like blue
Written out longer
The semicolons are only there because it is all on one line. In a file you would write it like this instead, and it means exactly the same thing.
for colour in red green bluedo echo $colourdone
A list of files
The list is usually a wildcard, and now the loop is doing real work: the same job to every file, however many there are.
Notice "$f" in quotes. A filename might have a space in it, and unit 7 lesson 2 is the reason this matters.
Terminal
kid@alguni:~$ for f in *.txt; do echo "--- $f"; cat "$f"; done --- a.txt one --- b.txt one two
Try it yourself
What does this print?
Terminal
for n in 1 2 3; do echo $(( n * 10 )); done
Answer it in the app
❓ Asking Questions
if, then, fi
The shell can decide. if runs a test, and if the answer is yes, everything up to fi happens.
fi is if backwards. Somebody in 1977 thought that was funny and we are all stuck with it.
Terminal
kid@alguni:~$ if [ -f notes.txt ]; then echo "the file is there"; fi the file is there kid@alguni:~$ if [ -f gone.txt ]; then echo "there"; else echo "not there"; fi not there
Three questions about a file
[ -f thing ] — is it a file?[ -d thing ] — is it a folder?[ -e thing ] — is it there at all?
The spaces inside the square brackets are not optional. [ is really a command, and a command needs a space after its name.
Terminal
kid@alguni:~$ if [ -d a-folder ]; then echo "folder"; fi folder kid@alguni:~$ if [ -f a-folder ]; then echo "file"; else echo "not a file"; fi not a file
Comparing numbers and words
For numbers: -eq equals, -lt less than, -gt greater than.
For words: = and !=.
They look odd, and the reason is that < and > were already taken — by redirection, back in unit 4.
Terminal
kid@alguni:~$ N=7 kid@alguni:~$ if [ $N -gt 5 ]; then echo "big"; else echo "small"; fi big kid@alguni:~$ WORD=cat kid@alguni:~$ if [ "$WORD" = "cat" ]; then echo "it is a cat"; fi it is a cat
Try it yourself
Why is it -gt and not >?
- Because `>` already means "send the output to a file"
- Because the shell cannot do numbers
- Because `>` is hard to type
- They both work the same
Answer it in the app
🌀 Again and Again
Keep going while
for runs once per thing in a list. while keeps going for as long as a test is still true.
So something inside the loop has to change, or it never stops.
Terminal
kid@alguni:~$ i=1 kid@alguni:~$ while [ $i -le 3 ]; do echo "line $i"; i=$(( i + 1 )); done line 1 line 2 line 3
The one that never stops
Forget the line that adds one and i stays 1 for ever. The test is always true, and the loop runs until you stop it.
On a real machine you press Ctrl and C. On this one the shell counts to 5000 and then stops and tells you which loop to look at.
Terminal
kid@alguni:~$ i=1 kid@alguni:~$ while [ $i -le 3 ]; do echo hello; done hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello bash: This program has run 5000 commands and shows no sign of stopping. A loop that never ends is the usual reason — check the `while`.
Try it yourself
Why does that loop never end?
- Nothing inside it ever changes `i`
- The test is wrong
- `echo` is too slow
- It needs `done` twice
Answer it in the app
🏆 Four Hundred Files
The promise from lesson one
Right at the start of this track it said: clicking is lovely for one file and horrible for four hundred.
This is where that gets paid off. Everything below would be an afternoon of clicking, and is one line of typing.
Try it yourself
What is the difference between for and while?
- `for` goes through a list; `while` keeps going until a test stops being true
- `for` is faster
- `while` can only count
- They are the same thing written differently
Answer it in the app