Tool Tip: “Read” – it does what it says!

read is a very useful tool; it might seem too simple to bother mentioning, but there are at least three different ways to use it. (Okay, two, and the third isn’t really anything special about read, just a nifty thing that the shell itself provides)…

1. Read the whole line

Let’s start with an interactive script:

$ cat readme.sh
#!/bin/sh
echo "I'm a parrot!"
while read a
do
    echo "A is $a"
done
$ ./readme.sh
I'm a parrot!
hello
A is hello
one two three
A is one two three
piglet eeyore pooh owl
A is piglet eeyore pooh owl
^D
$

Yes, you’ll need to hit CTRL-D to exit this loop, it’s just a simple example.

So far, so stupid. But wait; what if I wanted to get that “one” “two” “three” and use them differently?

2. Read the words

$ cat readme.sh
#!/bin/sh
echo "I'm a parrot!"
while read a b c
do
        echo "A is $a"
        echo "B is $b"
        echo "C is $c"
done
$ ./readme.sh
I'm a parrot!
hello
A is hello
B is
C is
one two three
A is one
B is two
C is three
piglet eeyore pooh owl
A is piglet
B is eeyore
C is pooh owl
^D
$

So, just by naming some variables, we can pick what we get. And – did you see that last one? We don’t lose anything, either… Just because we asked for three variables (a, b, c) and we got 4 values (piglet eeyore pooh owl), we didn’t lose anything; the last one was treated like a normal read.

This is actually pretty handy stuff; you’d have to do a bit of messing about with pointers to get the same effect in C, for example.

3. Read from a file

We can do all this from a file, too. This isn’t special to read, but it’s often used in this way. See that “while – do – done” loop? It’s a sub-shell, and we can direct whatever we want to its input (everything is a file, remember, so the keyboard, a text file, a device driver, whatever you want, it’s all just a file)

We do this with the “<” operator. Just add “< filename.txt” after the “done” end of the loop:

$ cat readme.sh
#!/bin/sh
echo "I'm a parrot!"
while read a b c
do
        echo "A is $a"
        echo "B is $b"
        echo "C is $c"
done  < myfile.txt
$ cat myfile.txt
1 2 3
4
5 6
7
8 9 10 11 12 13
14
15 16 17
$  ./readme.sh
I'm a parrot!
A is 1
B is 2
C is 3
A is 4
B is
C is
A is 5
B is 6
C is
A is 7
B is
C is
A is 8
B is 9
C is 10 11 12 13
A is 14
B is
C is
A is 15
B is 16
C is 17

So we can process tons of data, wherever it comes from.

4. I only mentioned 3 uses

We could make the script a bit more useful, by allowing the user to specify the file, instead of hard-coding it to “myfile.txt“:

$ cat readme.sh
#!/bin/sh
echo "I'm a parrot!"
while read a b c
do
        echo "A is $a"
        echo "B is $b"
        echo "C is $c"
done < $1
$ cat someotherfile.txt
123
1 2 3
one two three four
$ ./readme.sh someotherfile.txt
I'm a parrot!
A is 123
B is
C is
A is 1
B is 2
C is 3
A is one
B is two
C is three four
$

Update 14 April

Updated to fix the “done < filename.txt” from the example code of the last two examples.

Leave a comment