So far every value was written into the script. A useful script asks the person running it for information and responds to what they type. The person running a program is called its user, and what they give the program is its input.
read takes one line
The command read waits for the user to type a line and press Enter, and stores that line in a variable. A message that tells the user what to type is called a prompt.
echo "What is your name?"
read -r name
echo "Hello, $name!"If the user types Ada, the whole conversation on the screen looks like this:
What is your name?
Ada
Hello, Ada!Three details:
readis followed by the name of the variable to fill, written without a$. As with an assignment, you use the bare name to set a variable and$nameto read it.-ris an option: a setting that starts with a dash and changes how a command behaves.-rtellsreadto take the line exactly as typed. Without it,readtreats the backslash character\as special. Writeread -revery time.- The second line of the conversation,
Ada, was typed by the user. The script printed only the first and third lines.
Running scripts that read input
This example has no Edit & run button, because a button cannot stop and wait for you to type. Run it in the Bash playground instead:
- Copy the script into the editor.
- Open Standard input below the output and type what the user would type, one answer per line. For this script, type
Ada. - Press Run.
"Standard input" is the name programmers use for the stream of text that a program reads, which is normally the keyboard. On this site the script runs on our server, so you provide the typed lines in advance. Because nobody types on the screen there, the output shows only what the script printed: What is your name? and Hello, Ada!. The script has still read Ada exactly as it would from a keyboard.
On your own computer, bash hello.sh behaves exactly as the conversation above shows: the script stops at each read and waits for you.
A prompt on the same line
Often the answer looks better on the same line as the question. echo always ends its line, so use printf without \n, and end the prompt with a space:
printf 'What is your name? '
read -r name
echo "Hello, $name!"What is your name? Ada
Hello, Ada!Both styles are common. The exercises in this unit print each prompt on a line of its own with echo, because that is clearer to check.
In other people's scripts you may see read -r -p "What is your name? " name. The -p option shows a prompt, but only when a person is typing at a terminal. When the input is supplied in advance, as it is on this site, -p shows nothing. A prompt printed with echo or printf behaves the same everywhere.
What read stores is text
To Bash, every value is text. When the user types 36, the variable holds two characters, a 3 and a 6. Inside a string those characters are only pasted in:
answer="36"
echo "$answer + 1"
echo "$(( answer + 1 ))"This prints 36 + 1 and then 37. The first line is a string with a value placed in it; no arithmetic happens. Inside $(( )) Bash reads the digits as the number thirty-six and calculates. So in Bash, turning typed text into a number takes no extra step, but the calculation must be inside $(( )).
read stores them as text. Inside $(( )) Bash reads that text as the number 36, and only there does + 1 mean arithmetic.echo "How old are you?"
read -r age
next_year=$(( age + 1 ))
echo "Next year you will be $next_year."The shape of an interactive script
Most small programs follow the same four steps: prompt, read, compute, print.
Here is the whole shape in one script. It asks for the sides of a rectangle and prints its area. Each read takes the next line the user types, so two questions need two read commands.
echo "Width in metres?"
read -r width
echo "Height in metres?"
read -r height
area=$(( width * height ))
echo "Area: $area square metres"With 3 and 4 typed as the two answers, it prints the two questions and then Area: 12 square metres. Try it in the playground with two lines of standard input.
Four things that go wrong
Forgetting $(( )). There is no error message; the output is the giveaway. If you see 36 + 1 where you expected 37, the calculation is sitting inside a string.
A $ after read. read -r $age is wrong: it should be read -r age. Bash replaces $age with its value, which is empty at that point, so read is given no variable name and age stays empty. Again there is no message, only a missing value in the output.
Text that is not a whole number. If the user answers 3 apples to the age script above, the arithmetic fails and the script stops:
solution.sh: line 3: 3 apples: arithmetic syntax error in expression (error token is "apples")Read it in parts: line 3 is the line with $(( )); 3 apples is the value Bash was asked to calculate with; the "error token" is the part it could not read as arithmetic. The typed text was the problem, and line 3 is where it was noticed. A decimal such as 3.5 gives the same kind of message, because Bash has no decimal arithmetic.
A single word is worse, because it gives no message at all. If the user types ten, the script prints Next year you will be 1. Inside $(( )) a word is taken as a variable name, and a variable that was never set counts as 0. For now, assume the user types sensible whole numbers; later courses show how to check.
Reading more than was typed. On this site, a read that finds no line left stores nothing, and the script carries on with an empty variable. In arithmetic an empty variable counts as 0. If a result looks as if an answer was ignored, check that Standard input has one line for every read.
What you can do now
You can prompt the user, read a line, calculate with it and print a result that depends on what was typed. In the exercises you will predict what scripts print from given answers, then write a script that holds a short conversation.
Next: make decisions, so that a script can respond differently to different answers.