CSc 250: Lecture Notes: reading from stdin

Reading from standard input

When we were learning bash, many of our scripts accepted user input values on the command line. This was accomplished by using command-line arguments, and using the ${1}, ${2}, ${3},… variables to get the values that the user typed. Though we have not learned about it yet, this can also be done when writing python code. Before learning about processing command line arguments in python, we are going to discuss about reading text from standard input.

In python, we can read text from the command line entered by a user while the program is running. By doing this, we can make our program “interact” with a user, based on the text that the user types. Below is a very simple animated example:

In the above example, we executed typing.py with python3.6. The program starts up, prints out PROGRAM: Type something, then hit Enter:, and then waits for the user to type something. The program is still running while waiting, but it won’t do anything until text is types and then the Enter key is pressed. Once it is, the program reports what was typed, and then asks for more input. This process would continue forever, or until the program is killed. This is obviously a silly example, but using this technique we can write really cool programs, that “react” to human input.

First, let’s study how to implement the “silly” example, and then we will apply it to a more complex program.

For starters, how can we read text that is typed on the command-line? For this, we will use a function in the sys module, which is built-in to python. So first, we import it:

import sys

The function that we need is called readline(), and it can be called via:

sys.stdin.readline()

When this is executed, it tells the python program to wait for a full line of text input coming from standard input. Whatever input it receives is returned by this function call. Thus, we can store the input into a variable by writing:

user_input = sys.stdin.readline()

This will store exactly what the user types into user_input. However, doing this will also cause a new-line character to be included at the end (because the user hits Enter). To get rid of the training newline, we can write:

user_input = sys.stdin.readline().rstrip()

Adding rstrip() will remove any excessive whitespace (including new lines) from the end of a string. For now, we are not going to talk in-depth about how it works, just know that it does.

A complete program using this function would look like so:

import sys

print('PROGRAM: Type something, then hit Enter:')
user_input = sys.stdin.readline().rstrip()
print('PROGRAM: You typed: "' + user_input + '"')

Let’s put this in a file named typing.py and try it out:

This works similarly to the original example, but it only accepts a single line of input, and then exits after it has read it in a prints a massage to the user. The original screen recording that we saw repeatedly asked the user to “Type something, then hit Enter” and it did so forever, or until the program was exited (control-c). How can this be achieved? In this case, it is rather simple. Essentially, we want the last three lines of the above program to repeat indefinitely, and we should already know how to do this. While loops!

import sys

while True:
    print('PROGRAM: Type something, then hit Enter:')
    user_input = sys.stdin.readline().rstrip()
    print('PROGRAM: You typed: "' + user_input + '"')

This change will make typing.py behave like the original example.

At this point, we have written a complete python program that “interacts” with the user.

A few weeks ago we wrote a script in bash that produced a MadLib, based on words passed to the script via command-line arguments. Let’s write a MadLib script in python named madlib.py. However, unlike the bash script, we will get each input word by reading it from what a user types in standard input. To do this, we will use the same sys.stdin.readline().rstrip() function that we used in the last example.

madlib.py would look something like this:

import sys 
 
 print('Enter a name:')
name_a = sys.stdin.readline().rstrip()

print('Enter another name:')
name_b = sys.stdin.readline().rstrip()

print('Enter an adverb:')
adverb = sys.stdin.readline().rstrip()

print('Enter an adjective:')
adjective = sys.stdin.readline().rstrip()

print('Enter a city or country name (real or fictional):')
location = sys.stdin.readline().rstrip()

print('\n--- The Story of ' + name_a + ' and ' + name_b + '---\n')
print(name_a + ' and ' + name_b + ' were best friends who both lived in')
print('the peaceful land of ' + location + '. One day, they saw a ' + adjective)
print('grizzly bear wreaking havok in the streets. They ' + adverb + ' got their')
print('swords out and slew the beast.')
print('... The End.\n')

In the first few lines, we take as input 5 different categories of word. Once we have read them all in, they will be used to construct the MadLib story that it printed to stdout. Below is an example run:

Notice how each time one of the lines containing sys.stdin.readline().rstrip() is reached, the program “pauses” so that it can read input from a user.

Let’s go over one more example, that does some comparison based on input read in from stdin. Below is the contents of a python script named distance.py that does exactly this.

import sys 
 
 print('Distance to convert:')
distance = sys.stdin.readline().rstrip()

print('Input measurement standard (in, ft, mi):')
mes_in = sys.stdin.readline().rstrip()

print('Output measurement standard (mm, m, km):')
mes_out = sys.stdin.readline().rstrip()

in_value = float(distance)

if mes_in == 'in':
    pass # do nothing in here
elif mes_in == 'ft':
    in_value = in_value * 12
elif mes_in == 'mi':
    in_value = in_value * 63360

out_value = 0 

if mes_out == 'mm':
    out_value = in_value * 25.4
elif mes_out == 'm':
    out_value = in_value * 0.0254
elif mes_out == 'km':
    out_value = in_value * 0.0000254

print( distance + mes_in + ' ---> ' + str(out_value) + mes_out)

distance.py is a script that will convert a distance from one measurement standard to another. As you can probably tell, this program reads three values from standard input using the same functions as the earlier examples.

First, it reads in a numeric distance to convert. Second, it reads in a measurement standard that the input value is specified in. “in” for inches, “ft” for feet, and “mi” for miles. Third, it reads in a measurement standard to convert the input distance to. “mm” for millimeters, “m” for meters, and “km” for kilometers.

After reading in these values, the input distance is converted from a string to a float, so that the program can do the appropriate mathematical operations on the input.

The first if/elif chain determines what measurement standard the input distance is supposed to be. If it is inches, nothing needs to be done. If it is feet, the in_value is converted from feet to inches by multiplying by 12. If it is miles, the in_value is converted from miles to inches by multiplying by 63360.

The first if/elif chain determines what measurement standard to convert the input distance to. In each case, it multiplies in_value by the appropriate value multiplier, and then saves the result to out_value.

Finally, the resulting conversion in printed to standard output.

Below is a recording of running this program a few times.


(This problem stolen from lab 5 :-). Write a python program named quiz.py. This program will be an interactive quiz, and will read user answers in from standard input. If you forgot how to read lines from standard input, check out lecture notes 9.

This program will ask the user three questions, one by one. The user will type a response to each question on the command line, and then hit enter. Below are a few example runs of this quiz. You should be able to “reverse-engineer” the implementation of this quiz given the example runs below.

$ python3.6 quiz.py 
Q1: What bash command is used to search for strings?
grep
CORRECT!
Q2: What bash command is used to list files?
ls
CORRECT!
Q3: What is Ben's favorite noodle?
spaetzle
CORRECT!
$
$ python3.6 quiz.py 
Q1: What bash command is used to search for strings?
sed
WRONG! The correct answer is "grep"
Q2: What bash command is used to list files?
listing
WRONG! The correct answer is "ls"
Q3: What is Ben's favorite noodle?
bowtie
WRONG! The correct answer is "spaetzle"
$