More small fry Unix commands

Unix Insider –

Last month I started a series on Unix's smaller but no less useful commands. This month we continue the series.

read

The

<font face="Courier">read</font>
command is not actually a separate program in the Korn shell. It is built into the Korn shell. Its purpose is to allow input information to be read from standard input (usually the keyboard). In order to try out
<font face="Courier">read</font>
, type
<font face="Courier">ksh</font>
and press Enter.

Type the following command, and then enter a single word with no spaces as in the example below. The command

<font face="Courier">read x</font>
causes input to be read from standard input and assigned to the variable $x, which is then echoed to the screen.

<font face="Courier">$ read x; echo $x
hello
hello
$
</font>

<font face="Courier">read</font>
is usually used in shell scripts to accept user input and assign it to a variable. The following example, simpmenu, is a two-pick menu that uses
<font face="Courier">read</font>
to accept the user's input.

A menu is displayed at lines 7 through 18. At line 19 the user selection is accepted into the variable x and then one of two possible actions is executed at lines 20 through 23 and 25 through 28. This action is repeated until the user enters the number 9 as a menu pick. This is controlled at line 5. If $x is not equal (

<font face="Courier">-ne</font>
) to 9 at line 5 then the loop continues to execute.

Note the additional

<font face="Courier">read</font>
s at lines 22 and 27. These
<font face="Courier">read</font>
s seem to have no variable named for the input. The
<font face="Courier">read</font>
command supplies a default variable named REPLY. That is used if no variable is named with the
<font face="Courier">read</font>
command. I am only using
<font face="Courier">read</font>
at lines 22 and 27 to give the user the opportunity to see the last page of output before the screen is cleared.

<font face="Courier"> 1   # simpmenu
 2   # a simple menu program
 3   
 4   x=1
 5   while [ $x -ne 9 ]
 6   do
 7       clear
 8       echo
 9       echo
10       echo "Enter your selection"
11       echo
12       echo
13       echo "1  Display directory"
14       echo "2  Display processes"
15       echo
16       echo
17       echo "9  Exit"
18   
19       read x
20       if [ $x -eq 1 ]
21       then
22           ls -l|more ; echo "Press Enter" ; read
23       fi
24   
25       if [ $x -eq 2 ]
26       then
27           ps -ef|more ; echo "Press Enter" ; read
28       fi
29   done
</font>

Using the default REPLY variable, the first exercise could be shortened to:

<font face="Courier">$ read; echo $REPLY
hello
hello
$
</font>

The

<font face="Courier">read</font>
command can be used to read and fill more than one variable. Enter the following command and then type four words separated by a space:

<font face="Courier">$ read x y z; echo $x; echo $y; echo $z
one two three four
one
two
three four
$
</font>

The

<font face="Courier">read</font>
command reads in all of the words on a line and assigns them one by one to the variables listed for the
<font face="Courier">read</font>
command. If there are more words than there are variables, the remaining words are all assigned to the last variable. Thus $x=one, $y=two and $z=three and four.

This is true even with only one variable, as in the following listing. The $x variable is the last variable associated with

<font face="Courier">read</font>
, and so it ends up with the value one two three four:

<font face="Courier">$ read x; echo $x
one two three four
one two three four
$
</font>

You can break up the list in $x by using

<font face="Courier">for</font>
, as follows:

<font face="Courier">$ read x; for name in $x; do echo $name; done
one two three four
one
two
three
four
$
</font>

In the multmenu listing, the user can actually enter more than one menu pick separated by spaces. At lines 20 through 34, the user selection is broken into pieces and each individual piece is processed in multiple passes.

<font face="Courier"> 1   # multmenu
 2   # a multiple menu program
 3   
 4   x=1
 5   while [ $x -ne 9 ]
 6   do
 7       clear
 8       echo
 9       echo
10       echo "Enter your selection"
11       echo
12       echo
13       echo "1  Display directory"
14       echo "2  Display processes"
15       echo
16       echo
17       echo "9  Exit"
18       read x
19       for pick in $x
20       do
21          if [ $pick -eq 1 ]
22          then
23              ls -l|more ; echo "Press Enter" ; read
24          fi
25          if [ $pick -eq 2 ]
26          then
27              ps -ef|more ; echo "Press Enter" ; read
28          fi
29          if [ $pick -eq 9 ]
30          then
31              exit
32          fi
33       done
34   done

</font>

Reading from another process

The

<font face="Courier">read</font>
command possesses one other very powerful trick. It's possible to start a process running that produces output, and then read that output as if it were coming from the keyboard. This requires two steps:

  1. The process has to be started in a special way
  2. The
    <font face="Courier">read</font>
    command has to be informed that it is reading from another process rather than from the keyboard

The listing for oldest uses this technique. The

<font face="Courier">ls -tr</font>
command lists the file in a directory in oldest-to-newest order. The first entry in the list is therefore the oldest. At line 4 the
<font face="Courier">ls -tr</font>
command is launched but ends with a pipe bar and an ampersand (
<font face="Courier">|&</font>
). The ampersand indicates that the command is to be detached and run as a background command. The pipe indicates that a pipeline is to be created between oldest and the detached process. At line 6
<font face="Courier">read</font>
is issued with the -p flag meaning that it is to read from the pipe rather than from standard input. The read only goes up to the first newline character, so it only reads the first line that is output by the
<font face="Courier">ls -tr</font>
command.

<font face="Courier">1   # oldest
2   # names the oldest file
3
4   ls -tr|&
5
6   read -p x
7
8   echo "The oldest file is" $x
</font>

The next section on

<font face="Courier">wc</font>
includes another example of using
<font face="Courier">read</font>
. The
<font face="Courier">read</font>
command is more than simple input, and can be used for diverse tasks.

wc

The

<font face="Courier">wc</font>
command provides a count of words, lines, and characters in a document. In the listing below, log.txt contains 154 lines, 918 words, and 4431 characters. An
<font face="Courier">ls -l</font>
listing also reveals the size of the file to be 4431 bytes in length.

<font face="Courier">$ wc log.txt
  154  918  4431 log.txt
$ ls -l log.txt
-rw-r--r--   1 mjb  group      4431 Apr 12 14:35  log.txt
</font>

The word counter defines a word as any non-blank sequence of letters or numbers.

You may limit the output of

<font face="Courier">wc</font>
to a count of words, lines, or characters only by using the -w,-l, and -c switches respectively. The default is to display all three values. You may also display the results for more than one file as the file name is displayed for each entry along with a total. The following example displays the line counts for all files that start with log along with a total:

<font face="Courier">$ wc -l log*
  154  log.txt
    5  logit.sh
  159  total
</font>

The

<font face="Courier">wc</font>
utility is useful for authors. The listing for ueditor is my own personal editor that I use to check word counts (just kidding). It includes line numbers for explanation. The script is invoked using the command
<font face="Courier">ueditor article.txt</font>
. At line 3
<font face="Courier">wc</font>
is used to count words. The terminator
<font face="Courier">|&</font>
causes the
<font face="Courier">wc</font>
command to be started as a background task, and opens a pipe from ueditor to the background task in such a way that the results of the task can be read as input by ueditor. The result is read at line 4. The
<font face="Courier">wc -w</font>
command outputs two fields: the word count and the file name. These are read into separate variables: $wrds and $name at line 4. The value in $wrds is tested at line 5; if it is less than (
<font face="Courier">-lt</font>
) 2000, then words of encouragement are printed. If $wrds is 2000 or more, then the message contains some praise for your humble and hard-working author.

<font face="Courier">1   # ueditor
2   # checks if the article has 2000 words yet
3   wc -w $1|&
4   read -p $wrds $name
5   if [ $wrds -lt 2000 ]
6   then
7       echo "Only" $wrds "words! More, more I'm still not satisfied."
8   else
9       echo "A brilliant piece!"
10   fi
</font>
Insider: How the basic tech behind the Internet works
Join the discussion
Be the first to comment on this article. Our Commenting Policies