Guild Companies, Inc.  
 
Midrange Programmer - How-To Advice & Free Code
OS/400 Edition
Volume 1, Number 9 - May 9, 2002

The Ins and Outs of Qshell

by Ted Holt

Hello, Qshell fans! In the last lesson, you learned about stream I/O. If you have not read that article, it would be good for you to do so now, because some of the concepts mentioned in this article were explained there. In today's lesson, you're going to learn about some basic input and output commands you can use in Qshell scripts. Soon you'll be quite the authority on using stream files in Qshell scripts.

Read

Qshell has only one utility for reading stream files, cleverly named read. The read utility reads a line of data from a file and assigns the data to one or more variables. The default input file is standard input (stdin), but you can also read from other files using redirection or file descriptors. (This was discussed in the previous article.)

The data is usually text data, not binary data. That is, you get everything up to an end-of-line character (usually the carriage return and linefeed sequence). If a line ends with a backslash (\) followed immediately by the end-of-line sequence, Qshell assumes that the input data is continued on the next record of input. However, if you use the -r option, the backslash is not treated as a continuation character.

The following file contains four records, but Qshell will read them as three records if the -r option is not specified:

This is one line of input.
This is \
another line of input.
This is the third line of input.

The word read may be followed by options or variable names. Let's consider variable names first.

When the read utility reads a record, it separates the contents of the record into fields. The value in the IFS (internal field separator) variable tells the read utility how to separate the data. Normally, IFS is set to a binary zero, which means that fields are separated by white space--one or more blanks, tabs, or newline characters.

Qshell fills in the variables with the field values until it runs out of data or variables. If there are more data values than variables, all remaining data values are placed in the last variable.

Examine the following script fragment. Notice that the IFS variable is set to a comma. This script reads a CSV (comma-separated values) file:

IFS=',' 
read name age phone 

Assume this input data:

Bill,11,1-888-SHOP-IBM

After the read finishes, the variable name is Bill, the variable age is 11, and the variable phone is 1-888-SHOP-IBM.

Qshell permits three options. (Other Unix shells permit more.) I have already mentioned the -r option, which disables the backslash line-continuation character. There is also option -u, which makes Qshell read from a file that was opened with a file descriptor. (I discussed file descriptors in the last article.)

The other option is -p, which allows a prompt string to be displayed on standard error. Here's an example:

read -p "Please enter your name:" name

I don't recommend that you use this option, because the prompt only displays when the script is run with the dot operator, and the dot operator is not the way you will usually want to run Qshell scripts.

Echo

While there is only one input utility, there are several Qshell output utilities. The easiest (and least powerful) one is echo, which sends one or more arguments, followed by an end-of-line sequence, to standard output (stdout).

The word echo can be followed by one or more arguments separated by white space. An argument can be a quoted string, an unquoted string, or a variable. Quoted strings may be delimited with single (') or double (") quotation marks. Single quotation marks are "strong" quotes, and don't allow the system to substitute values for variables inside the quoted strings. (See "Working with Parameters and Variables in Qshell Scripts" for more about single and double quotation marks.)

Suppose this echo command runs with the variables defined as in the preceding section:

echo "$name is $age years old."

Here's the output:

Bill is 11 years old.

Print

Print is echo, but with more muscle. Print beats echo in two ways: Print allows options, and it can interpret control commands within the arguments it sends to output files.

There are three allowable options: -n, -r (or -R), and -u. The -n option tells print not to advance to a new line after printing the arguments. In the following example, both print statements print to one line of output:

 print -n "Hello "               
 print $name                     

If the name variable has the value Bill, this is the output:

 
Hello Bill

The -u option tells print to send output to the file opened under a certain file descriptor.

The -r (or -R) option tells print not to interpret the control characters in the arguments.

The control characters begin with a backslash and are listed in the following table:

Character

Description

\a

sound the terminal's alarm

\b

backspace one character

\c

ignore subsequent arguments and suppress newline

\f

formfeed (clears the screen)

\n

newline (carriage return and linefeed)

\r

return (carriage return, but no linefeed; returns to beginning of the line)

\t

tab

\v

vertical tab (linefeed, but no carriage return; moves cursor down)

\0x

EBCDIC character; x is a 1-, 2-, or 3-digit decimal number

Here are some examples of print and the output it produces:

Command

Output

print "a\bc"

c

print "a\tb"

a       b

print "a\nb"           

a

b

print "a\vb"

a

  b

print "abcde\rfgh"

fghde

To include a backslash in a string, you normally code two backslashes, although one backslash if often sufficient. However, if the character following the backslash is a control character, you will have to code three backslashes to print one. Consider this example:

print "Look in directory c:\\\temp\\mystuff\\zipfiles."

Qshell produces this output:

Look in directory c:\temp\mystuff\zipfiles.

If I leave only two backslashes after the colon, Qshell interprets the \t as a tab and drops the backslash that follows the colon. The Qshell manual does not tell me why this behavior occurs.

If you code a single backslash before any character other than the ones mentioned above, the behavior is undefined and unpredictable. You may get a backslash in the output, and, then again, you may not.

Printf

The printf utility is based on C's printf function and differs from Qshell's print utility in several ways. First, printf provides a way to format the way variables are printed. Second, printf does not automatically generate an end-of-line sequence when it writes. If you want to advance to a new line, you must include a \n control sequence in the format string. Third, printf does not support the print options. For instance, you cannot use the -u option to direct print to a certain file; you will have to use a file descriptor with redirection operators.

You must provide at least one argument--a format string--to printf. The format string may contain plain text, control characters, and special formatting sequences.

Printf supports the control sequences that print supports. That is, you can use \t to tab, \b to backspace, and so on. I just said it, but it bears repeating: The printf utility does not linefeed after printing unless there is a \n sequence in the format string.

A formatting sequence has the following syntax:

%[flags][width][.precision]conversion

The brackets ([]) indicate optional portions and are not coded.

Since the conversion character is the only required portion of a formatting sequence, let's look at it first. You must include a conversion character to tell printf how to format an argument:

Character

Description

Acceptable data types

c

unsigned character

Character

d

signed decimal number

Integer

e, E

scientific notation

Real

f

print as a real number

Real

g, G

scientific notation with significant digits

Real

i

signed decimal number (same as d?)

Integer

o

unsigned octal number

Integer

s

string

Character

u

unsigned decimal number

Integer

x

unsigned hexadecimal number with lowercase a-f

Integer

X

unsigned hexadecimal number with uppercase A-F

Integer

For example, %d means that a number is to be printed in decimal format, while %o means a number is to be printed in octal format.

Printf applies the other arguments to the conversion characters in the format string. If printf finds more arguments than conversion characters, it reuses the format string as often as necessary. For example, if there are two conversion characters in the formatting string, but four arguments following the conversion string, printf will use the formatting string twice.

Now is also a good time to mention how to print a percent sign (%). Since the percent sign is used to indicate the beginning of a formatting sequence, you must double any percent signs to be printed.

Here are some examples. Assume that name is Bill and age is 11.

Command

Output

printf "%c\n" $name

B

printf "%s\n" $name

Bill

printf "%d\n" $age

11                 

printf "%i\n" $age

11                 

printf "%o\n" $age

13                 

printf "%x\n" $age

b                  

printf "%X\n" $age

B                 ;  

printf "%f\n" $age

11.000000         

printf "%e\n" $age

1.100000e+01      

printf "%g\n" $age

11                 

printf "%s is %d years old.\n" $name $age

Bill is 11 years old.                     

printf "%d%%\n" 25

25%

printf "%d %d\n"  15 16 20 22

15 16

20 22

Notice the double percent sign in the next-to-last example and the reused format string in the last example.

You may use the optional portions of the formatting sequence--flags, width, and precision--to further modify the appearance of the output.

The five flags are used only with numeric values. You may use more than one of them in a formatting sequence. Here are the flags and their meanings:

Flag

Description

space

Precede positive values with space, negative values with -.

+

Precede positive values with +, negative values with -.

-

Left justify the output.

0

Display leading zeros.

#

Precede octal numbers with 0.

Precede hexadecimal numbers with 0x or 0X.

For real numbers, display the decimal point.

For g or G, display trailing zeros.

The width is the minimum number of characters to be sent to output. If you code an asterisk (*), the width is taken from the next argument:

Command

Output

Comment

printf "%5i\n" $age

   11

There are three leading blanks.

printf "%0*d\n" 4 7

0007

The length is 4; the value is 7.

The function of the precision depends on the conversion character:

Character

Description

d,i,o,u,x,X

minimum number of digits to be displayed

e, E, f

number of decimal digits to be displayed

g, G

maximum number of significant digits

s

maximum number of characters to be displayed

A technique you might find handy is to use printf to format variables. Here's an example:

amount=$(printf "$%-10.2f" $price)

If price has a value 245.3, amount takes the value $245.30, followed by four blanks, for a total length of 11. Let's see why.

Look at the format string in the printf command. The f means that the value is to be printed as a floating point (real) number. The 10 refers to the overall length of the number, including sign and decimal positions. The 2 means that two decimal positions are to be shown. The hyphen (-) means that the number is left-adjusted within the 10 positions. When the dollar sign ($), which is not part of the formatting sequence, is placed in front of the number, the total length is 11.

To load the output of printf into the variable called amount, use command substitution, a technique whereby the output of a command is substituted for the command itself. To tell Qshell to use command substitution, enclose the command within parentheses and precede it with a dollar sign.

Dspmsg

Another way to send output to stdout is with the display message (dspmsg) utility. This feature was designed to make it easier to use scripts with different national languages. Instead of hard-coding messages in your scripts, you store messages in a message catalog and use dspmsg to retrieve them. If you decide to run your scripts in an environment where people use another language, you translate the messages without having to modify the script.

You'll need a message catalog to hold the messages. Begin by creating the messages in a source physical file member. Here's an example:

$ My message catalog           
$quote '                       
$set 1                         
1 'File %s not found.\n'       
2 'File is a directory.\n'     
$set 2                         
1 'Directory not found.\n'     
2 'File is not a directory.\n'

The first line is a comment because it begins with a dollar sign and a space. The second line says that the single quote is used a quotation character to delimit the message text. The third line indicates that the following messages are in set 1. The two lines following define messages 1 and 2 of the set. The last three lines define two messages in set 2.

To create or update the message catalog, use either the Generate Message Catalog (GENCAT) or the Merge Message Catalog (MRGMSGCLG) CL command. Both commands are identical in function. The following command creates a message catalog called mymsgcat in the current directory from the source in member MYMSGCAT in MYLIB/MYSRC:

GENCAT +
   CLGFILE(mymsgcat) +
   SRCFILE('/qsys.lib/mylib.lib/mysrc.file/mymsgcat.mbr')                   

To display message 1 of set 2, use this command within a Qshell script:

dspmsg -s 2 mymsgcat 1

You may have noticed that message 1 of set 1 includes the substitution characters %s to indicate that a parameter will be passed to the message. To indicate that file x is not found, send message 1 of set 1 with a parameter of x, like this:

dspmsg mymsgcat 1  'File %s was not found.\n' x

If Qshell locates the message, the following string of characters is sent to stdout:

File x not found.

If the message is not located, the string in between the quotes is sent to stdout instead.

To learn more about message catalogs, see the System Planning and Installation manual.

The Ins and Outs

In the last issue, you learned about stream files. In this issue, you have learned how to gain flexibility when reading and writing stream data. I hope you see that while the Qshell language isn't as robust as other languages you may be familiar with, it should be adequate for your scripting needs.

Sponsored By
ASNA

Why Iredell Memorial Hospital Uses ASNA Visual RPG for Web Development

In an effort to help the most patients, doctors are always looking for the quickest and easiest way to get things done. At Iredell Memorial Hospital in Statesville, NC, the green screen application that accessed patient records and information was just not good enough. Scott Philemon was charged with the task of bringing this valuable information to a browser-based system and he found that AVR was the best way for him to do that. He has created a simple point-and-click system that is intuitive rather than the cumbersome green-screen system with which most doctors were uncomfortable. The most important feature of this new application is that doctors will be able to connect, via a modem, to this application and not have to make the trip into the hospital to check on the status of patient blood tests and other medical procedures.

"I was given this project and told to just find the best way to get it done. I heard java, java, java all the time so I took a couple of introductory classes and realized that I would spend a year just learning it before I would even be able to start on this project. With AVR I can really use my RPG skills to create browser-based applications. The transition was so easy and I'm so pleased with the results that I'm recommending that we do ONLY Web applications in the future."

—Scott Philemon, Iredell Memorial Hospital

ASNA Visual RPG (AVR) for Web, Windows and .NET Development

ASNA Visual RPG (AVR) is an integrated development environment for creating enterprise Web, Windows and .NET applications. Transparent database access; an integrated editor, compiler and debugger; support for emerging standards such as XML and SOAP; and equally powerful Web or Windows deployment possibilities make ASNA Visual RPG the one application development environment you can't afford to ignore! Use your RPG skills to develop Web, Windows and .NET applications today.

Download your FREE trial of AVR today!

http://www.asna.com/downloads.asp

THIS ISSUE
SPONSORED BY:
SoftLanding Systems
LANSA
ACOM Solutions
ASNA
Profound Logic Software
WorksRight Software
BACK ISSUES
TABLE OF CONTENTS
Creating a VARPG Appointment Calendar
Dynamic Selection with Embedded SQL
Validating XML with a Document Type Definition
The Ins and Outs of Qshell
The iSeries Toolbox for Java: GUI-izing Program Calls
Exploring iSeries Navigator Application Administration
  Newsletters | Subscribe | Advertise | About Us | Contact | Search | Home  
  Last Updated: 5/8/02
Copyright © 1996-2008 Guild Companies, Inc. All Rights Reserved.