Input/Output Commands

The Korn shell provides a number of input/output commands, which are covered in the following sections.

The print Command

You've already seen this command a hundred times since it was introduced in Chapter 3, but here it is again. This is a more formal definition of the command that describes the other things it can be used for. The print command displays arguments according to options with this format:

						print [options] arguments
					

Without options, special characters, or quotes, each argument is displayed separated with a space, and all the arguments are terminated with a newline:

						$ print X          Y          Z
						X Y Z
					

Notice that all the extra whitespace between the arguments was truncated. We could keep the whitespace by enclosing the arguments in quotes like this:

						$ print "X           Y          Z"
						X             Y            Z
					

Escape Characters

There are a number of special escape characters that allow you to format the print arguments. For example, to display arguments on separate lines, instead of using multiple print commands:

							$ print X; print Y; print Z
							X
							Y
							Z
						

the arguments could be separated with the newline escape character :

							$ print "X
Y
Z"
							X
							Y
							Z
						

Table 8.6. print Escape Characters
a bell character
 backspace
c line without ending newline (remaining arguments ignored)
f formfeed
newline
return
tab
v vertical tab
\ backslash
x 8-bit character whose ASCII code is the 1-, 2-, or 3-digit octal number x

The print arguments could be double-spaced like this:

							$ print "X

Y

Z"
							X
							Y
							Z
						

Make sure escape characters are enclosed in quotes. Otherwise they are not interpreted correctly. Here, without the quotes, is interpreted as an escaped 'n', and not as the newline escape character:

							$ print X
Y
Z
							XnYnZ
						

The character can also be used to quote the escape characters:

							$ print X\nY\nZ
							X
							Y
							Z
						

A tab can be displayed with the escape character:

							$ print "X	Y	Z"
							X     Y      Z
						

The c escape character causes the trailing newline to be dropped from the output. It is often used to create prompts.

							$ print "Enter choice: c"
							Enter choice: $
						

Notice that the command prompt was displayed following the argument, and not on the next line.

The escape character causes a carriage return without line feed to be displayed and can be used to format non-fixed length data. This command prints an R on the right side, then the escape character moves the cursor back to the beginning of the same line and prints an L on the left side followed by TEXT:

							$ print      '                R
LTEXT'
							LTEXT        R
							$ print '               R
L      TEXT'
							L        TEXTR
						

Notice that the L and R characters are lined up, while TEXT is in a different position in both commands. In the Bourne shell, this is the easiest way to display non-fixed-length data in a fixed-length format. In the Korn shell, the same display could be created by using a fixed-length variable. First, variable X is set to ten-character wide, left-justified with a value of TEXT. Notice that {}'s must be given to delimit the variable name X:

							$ typeset —L10 X=TEXT
							$ print "L${X}R"
							LTEXT        R
						

To right-justify the value of X, the right-justify attribute is set:

							$ typeset —R10 X
							$ print "L${X}R"
							L             TEXTR
						

This print command displays a message and beeps:

							$ print "Unexpected error!a"
							Unexpected error!<BEEP>
						

Using octal codes, the previous command could be given like this:

							$ print "Unexpected error!07"
							Unexpected error!<BEEP>
						

print Options

The print command has a number of options that affect the way its arguments are interpreted. The option is used if you want to print arguments that begin with a character. In the next command, without the argument, –Z is interpreted as an option and causes an error to be returned:

							$ print —Z
							/bin/ksh: print: bad options(s)
							$ print — —ZZ
						

The –n option is used when you don't want the trailing newline to be printed:

							$ print —n "Enter choice:"
							Enter choice:$
						

Table 8.7. print Options
treat everything following as an argument, even if it begins with –.
–n do not add a ending newline to the output.
–p redirect the given arguments to a co-process.
–r ignore the escape conventions.
–R ignore the escape conventions; do not interpret arguments as options (except –n).
–s redirect the given arguments to the history file.
–un redirect arguments to file descriptor n. If the file descriptor is greater than 2, it must first be opened with the exec command. If n is not specified, the default file descriptor is 1.

This is equivalent to:

							$ print "Enter choice:c"
							Enter choice:$
						

The –r option causes the special escape characters to be ignored. Here, is printed without interpretation as the tab character:

							$ print —r 'a	b'
							a	b
						

The –R option is the same as –r, except that it also causes arguments beginning with (except –n) to be interpreted as regular arguments and not as options.

							$ print —R — '—a	b'—a	b
						

The –s option redirects the given arguments to the history file.

							$ print —s "This is a history entry"
							$ history —2
							165   This is a history entry
							166   history —2
						

The –u option is used to redirect arguments to a specific file descriptor. Instead of displaying a message to standard error like this:

							$ print "This is going to standard error >&2
							This is going to standard error
						

the print –u2 command can be used.

							$ print —u2 "This is going to standard error"
							This is going to standard error
						

The echo Command

The echo command displays its arguments on standard output and is provided for compatibility with the Bourne shell. In the Korn shell, echo is an exported alias set to "print –".

The exec Command

The exec command is used to perform I/O redirection with file descriptors 0 through 9 using this format:

						exec
						I/O-redirection-command
					

The I/O redirection performed by the exec command stays in effect until specifically closed, changed, or if the script or shell terminates. We could use this idea to direct standard output to a file. First, let's start a subshell. You know that 1>std.out directs standard output to std.out. So if we put the exec command in front of it, all subsequent standard output will be redirected.

						$ ksh
						$ exec 1>std.out
					

Now anything that goes to standard output is redirected to std.out until file descriptor 1 is specifically reset.

						$ pwd
						$ whoami
						$ print "Where is this going?"
					

Notice that standard error is still attached to your terminal:

						$ print —u2 "This is going to standard error"
						This is going to standard error
					

Let's exit from the subshell, and take a look at the output file:

						$ exit
						$ cat std.out
						/home/anatole/bin
						anatole
						Where is this going?
					

Here, file redir.out is opened as file descriptor 5 for reading and writing:

						$ exec 5<>redir.out
					

Now the print command writes something to file descriptor 5:

						$ print —u5 "This is going to fd 5"
					

and the cat command reads from it:

						$ cat <&5
						This is going to fd 5
					

To finish up, we use another exec to close file descriptor 5:

						$ exec 5<&—
					

Any subsequent attempts to write to it or read from it would generate this error message:

						$ print —u5 "Trying to write to fd 5 again"
						/bin/ksh:  5: bad file unit number
					

Standard input can be taken from a file like this:

						exec 0<file
					

Commands could be read in from file, and it would be almost as if you typed them at your terminal.

The exec command can also be used to replace the current program with a new one. For example, you know that if you wanted to run the C shell, you could invoke it as a subshell like this:

						$ csh
						{aspd:1}
					

But why have the extra parent shell process hanging around if you don't need it? In this case, the exec command could be used to replace the current shell with the C shell:

						$ exec csh
						{aspd:1}
					

Now if you exited from the C shell, you would be logged out.

Here is another application. Remember the smenu script from the select command section? You could make a full-blown UNIX interface menu out of it by adding some more commands. If you wanted to set it up as a login shell, this would need to be added to a .profile file:

						exec smenu
					

and execution would be restricted to smenu.

The read Command

The read command is used to read input from a terminal or file. The basic format for the read command is:

						read
						variables
					

where a line is read from standard input. Each word in the input is assigned to a corresponding variable, so the first variable gets the first word, the second variable the second word, and so on. Here, "This is output" is read in to the variables X, Y, and Z. The first word of the input is This, so it is assigned to the first variable X. The second word is is, so it is assigned to the second variable Y. The third word is output, so it is assigned to Z.

						$ print "This is output" | read X Y Z
						$ print $X
						This
						$ print $Y
						is
						$ print $Z
						output
					

If there aren't enough variables for all the words in the input, the last variable gets all the remaining words. This command is the same as the last one, except that an extra string "again" is given.

						$ print "This is output again " | read X Y Z
						$ print $X
						This
						$ print $Y
						is
					

Table 8.8. read Options
–p read input line from a co-process
–r do not treat as the line continuation character
–s save a copy of input line in the command history file
–un read input line from file descriptor n. If the file descriptor is greater than 2, it must first be opened with the exec command. If n is not specified, the default file descriptor is 0.

Because there are four strings, but only three variables, Z gets the remaining unassigned words:

						$ print $Z
						output again
					

If one variable argument is given to the read command, it gets assigned the entire line. Here, the variable LINE is set to the entire line:

						$ print "This is output again" | read LINE
						$ print $LINE
						This is output again
					

The kuucp script could be modified so that it prompted for a source file and target system. This is just a bare-bones script that demonstrates the use of the read command. A usable version is included in Appendix D.

						$ cat kuucp
						PUBDIR=${PUBDIR:—/usr/spool/uucpublic}
						# Prompt for source file
						print —n "Enter source file: "
						read SOURCE
						# Prompt for remote system name
						print —n "Enter remote system name: "
						read RSYS
						print "Copying $SOURCE to $RSYS!$PUBDIR/$SOURCE"
						uucp $SOURCE $RSYS!$PUBDIR/$SOURCE
					

Here is some sample output:

						$ kuucp
						Enter source file: rt.c
						Enter remote system name: mhhd
						Copying rt.c to mhhd!/usr/spool/uucppublic/rt.c
					

Reading Input from Files

Besides reading input from your terminal, the read command is also used to read input from a file. The read command by itself will only read one line of input, so you need a looping command with it. To read in the contents of a file, use this format:

							exec 0<file
							while read
							variable
							do
							commands
							done
						

The exec command opens file for standard input, and the while command causes input to be read a line at a time until there is no more input. If the exec open on file fails, the script will exit with this error message:

							script-name:
							file: cannot open
						

Here is a stripped-down version of kcat. It is a simple version of the UNIX cat command. It displays the given file on standard output one line at a time.

							$ cat kcat
							exec 0<$1
							while read LINE
							do
							print $LINE
							done
						

In terms of performance, it is about 3-4 times slower than the UNIX cat command, but it will do for demonstration purposes. Here is sample output:

							$ kcat test.input
							1: All work and no play makes Jack a dull boy.
							2: All work and no play makes Jack a dull boy.
							3: All work and no play makes Jack a dull boy.
							. . .
						

The real version of the kcat command is listed in Appendix D.

Here is an alternate format that will also work for reading input from files:

							cat
							file
							| while read
							variable
							do
							commands
							done
						

On the systems tested, the exec format for reading input from files was about 40-60 times faster than the last version above. It may be different on your system, but that's still a significant performance improvement.

The IFS Variable

The read command normally uses the IFS (Internal Field Separator) variable as the word separators. The default for IFS is space, tab, or newline character, in that order, but it can be set to something else. It is useful for when you want to read data that is not separated with whitespace. In this example, IFS is set to a comma:

							$ IFS=,
						

then the print arguments are separated with the new word separator for read:

							$ print 'This,is,output' | read WORD1 WORD2 WORD3
							$ print $WORD1 $WORD2 $WORD3
							This is output
						

By setting IFS to :, the fields in the /etc/passwd file could be read into separate variables.

							$ cat ifs_test
							IFS=:
							exec 0</etc/passwd
							while read -r NAME PASS UID GID COMM HOME  SHELL
							do
							print "Account name=    $NAME
							Home directory=    $HOME
							Login Shell= $SHELL"
							done
						

Here is sample output:

							$ ifs_test
							Account name=root
							Home directory= /
							Login Shell= /bin/ksh
							Account name=anatole
							Home directory= /home/anatole
							Login Shell= /bin/ksh
							. . .
						

More with read

Another format for the read command is:

							read
							options [variables] 

where input is read and assigned to variables according to the given options. The –u option is used to read input from a specific file descriptor. If the file descriptor is greater than 2, then it must first be opened with the exec command. Let's look at the stripped-down version of kcat again. It could be changed to prompt to continue before displaying the next line like this:

							$ cat kcat
							exec 0<$1
							while read LINE
							do
							print $LINE
							print —n "Do you want to continue?"
							read ANSWER
							[[ $ANSWER = @([Nn])* ]] && exit 1
							done
						

Here is the test.input file again:

							$ cat test.input
							1: All work and no play makes Jack a dull boy.
							2: All work and no play makes Jack a dull boy.
							3: All work and no play makes Jack a dull boy.
							. . .
						

When the new version of kcat is run, the output looks strange. Can you figure out the problem? The reason is that we redirected standard input from test.input, but we are also expecting the input to ANSWER from standard input. In the first loop, line 1 from test.input is assigned to LINE. The next read command, which is inside the loop, reads the next line into ANSWER. In the second loop, we're up to line 3, so it gets assigned to LINE, and so on.

							$ kcat test.input
							1: All work and no play makes Jack a dull boy.
							Do you want to continue?3: All work and no play
							makes Jack a dull boy.
							Do you want to continue?
							. . .
						

Instead of redirecting standard input (file descriptor 0) from test.input, we could redirect it from another file descriptor and read it using the –u option. Then it wouldn't interfere with read ANSWER which is expecting input from standard input. Here is the new and improved version:

							$ cat kcat
							exec 4<$1
							while read -u4 LINE
							do
							print $LINE
							print —n "Do you want to continue?"
							read ANSWER
							[[ $ANSWER = @([Nn])* ]] && exit 1
							done
						

Now it works.

							$ kcat test.input
							1: All work and no play makes Jack a dull boy.
							Do you want to continue?<RETURN>
							2: All work and no play makes Jack a dull boy.
							Do you want to continue?<RETURN>
							3: All work and no play makes Jack a dull boy.
							Do you want to continue?n
							$
						

The –s option saves a copy of the input in the history file. Here is an example:

							$ print "This is a history entry" | read —s HVAR
						

Just to make sure, let's look at both the history file:

							$ history —2
							170   This is a history entry
							171   history —2
						

and HVAR:

							$ print $HVAR
							This is a history entry
						

Reading Input Interactively

The read command allows input to be read interactively using this format:

							read
							name?prompt
						

where prompt is displayed on standard error and the response is read into name. So instead of using two commands to display a prompt and read the input:

							$ print —n "Enter anything: "
							$ read ANSWER
						

The same thing can be done with one command.

							$ read ANSWER?"Enter anything: "
							Enter anything: ANYTHING
						

Here is ANSWER:

							$ print $ANSWER
							ANYTHING
						

Let's change the kuucp script (again) so that this format of the read command was used:

							$ cat kuucp
							PUBDIR=${PUBDIR:—/usr/spool/uucpublic}
							read SOURCE?"Enter source file: "
							read RSYS?"Enter remote system name: "
							print "Copying $SOURCE to $RSYS!$PUBDIR/$SOURCE"
							uucp $SOURCE $RSYS!$PUBDIR/$SOURCE
						

The REPLY variable

If no variables are given to the read command, the input is automatically assigned to the REPLY variable. Here, ANYTHING is read into REPLY:

							$ print ANYTHING | read
							$ print $REPLY
							ANYTHING
						

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.189.220