381 lines
11 KiB
Groff
381 lines
11 KiB
Groff
.TH compute "" "" "/rdb Command"
|
|
.PC "Calculate columns of a table"
|
|
\fBcompute '\fIcolumn \fB= \fIexpression \fB[ ; ... ]' < \fItableorlist\fR
|
|
.PP
|
|
.II "arithmetic^column"
|
|
.II "column^arithmetic"
|
|
.II "column^recompute"
|
|
The command
|
|
.B compute
|
|
lets you to do arithmetic on columns.
|
|
A column can be computed as a function of other columns, of itself,
|
|
and of constants.
|
|
.PP
|
|
.B compute
|
|
uses the COHERENT command
|
|
.B awk
|
|
to perform its work, as
|
|
does the command
|
|
.BR row .
|
|
.B awk
|
|
is a a powerful, interpreted programming language in which you can write
|
|
programs to perform complex transformations on text.
|
|
The advantage of
|
|
.B compute,
|
|
over
|
|
.B awk
|
|
is that
|
|
.B compute
|
|
knows about the names of columns in a table;
|
|
this permits you to use column names instead of column positional numbers.
|
|
(In
|
|
.B awk
|
|
the second column is named
|
|
.BR $2 .)
|
|
To grasp the full power of
|
|
.B compute
|
|
and
|
|
.BR row ,
|
|
read the COHERENT system's
|
|
.B awk
|
|
tutorial.
|
|
If you must perform very complex manipulations of tables, use
|
|
.BR awk .
|
|
.PP
|
|
If you must create a new empty column for
|
|
.B compute
|
|
to put values into, use the command
|
|
.BR column .
|
|
This command
|
|
creates an empty column for any
|
|
column it cannot find in the header line.
|
|
.SH Example
|
|
This example computes a column from other columns:
|
|
.DM
|
|
compute 'Value = sprintf("%5.2f", Cost * Amount)' < inventory
|
|
.DE
|
|
.DM
|
|
Item Amount Cost Value Description
|
|
---- ------ ----- ------ ---------------
|
|
1 3 5.00 15.00 rubber gloves
|
|
2 100 0.50 50.00 test tubes
|
|
3 5 8.00 40.00 clamps
|
|
4 23 1.98 45.54 plates
|
|
5 99 2.45 242.55 cleaning cloth
|
|
6 89 14.75 1312.75 bunsen burners
|
|
7 5 175.00 875.00 scales
|
|
.DE
|
|
.PP
|
|
Here are more examples of what you can do with compute.
|
|
You can change the format of \fBcolumn\fR by using a C-style
|
|
.BR sprintf :
|
|
.DM
|
|
compute 'column = sprintf ("%8.2f", column)' < tableorlist
|
|
.DE
|
|
.PP
|
|
You can
|
|
set \fBcolumn\fR equal to the length of the string in \fBcolumn2\fR:
|
|
.DM
|
|
compute 'column = length (column2)' < tableorlist
|
|
.DE
|
|
.PP
|
|
You can also
|
|
Set \fBcolumn\fR equal to the natural logarithm of \fBcolumn2\fR:
|
|
.DM
|
|
compute 'column = sprintf("%f", log (column2))' < tableorlist
|
|
.DE
|
|
.PP
|
|
Or, you can
|
|
increment \fBcolumn2\fR whenever \fBcolumn\fR is greater than \fBnumber\fR:
|
|
.DM
|
|
compute 'if (column > number) column2 = \e
|
|
sprintf("%d", column2+1)' < tableorlist
|
|
.DE
|
|
.SH Expressions
|
|
As you can see, you can write rather complex expressions for
|
|
.BR compute .
|
|
By
|
|
.I expression,
|
|
we mean many kinds of equations.
|
|
For example, a variable or a column is an expression.
|
|
So is variable + variable. So are rather complex equations.
|
|
The following symbols indicate some of the more complex expressions:
|
|
.IP \fBcolumn\fR 0.3i
|
|
Name of a column, exactly as it appears at the top of the column.
|
|
.IP \fB\(eq\fR
|
|
Make the column on the left equal the expression on the right.
|
|
.IP \fB+\fR
|
|
Add
|
|
.IP \fB\-\fR
|
|
Subtract
|
|
.IP \fB*\fR
|
|
Multiply
|
|
.IP \fB/\fR
|
|
Divide.
|
|
.IP \fB%\fR
|
|
Modulo (zero if left value is equally divisible by right).
|
|
.IP \fB;\fR
|
|
Statement separator needed if more than one equation
|
|
.IP \fBlog()\fR
|
|
Natural logarithm of value or column within parentheses.
|
|
.IP \fBlength()\fR
|
|
String length of string in column.
|
|
.PP
|
|
You can also use C language-like statements:
|
|
.IP "\fBif (\fIexpression\^\fB) \fIequation\fB [ else \fIequation\fB ];\fR"
|
|
For example:
|
|
.DM
|
|
if (Value > 10000) Status = "Special"; else Status = "Normal";
|
|
.DE
|
|
.IP "\fBwhile (\fIexpression\fB) \fIequation\fB;\fR
|
|
For example:
|
|
.DM
|
|
while (column => 0) column -= 1 ;
|
|
.DE
|
|
.IP "\fBfor (\fIexpression\fB; \fIcondition\fB; \fIexpression\fB) \fIequation\fB;\fR"
|
|
For example:
|
|
.DM
|
|
for (i = 0; i < column1; i++) array [i] = column2 + i ;
|
|
.DE
|
|
.PP
|
|
You can also use the
|
|
.B awk
|
|
format \fIpattern \fB{ \fIaction \fB}\fR.
|
|
For example:
|
|
.DM
|
|
compute 'length > 80 { print NR, "Line too long." }' < table
|
|
.DE
|
|
.PP
|
|
.B awk
|
|
recognizes
|
|
.I length
|
|
as a function that returns the length of the row and
|
|
.B NR
|
|
as the line number.
|
|
Note that the line numbers of a file starts with the head line,
|
|
while row numbers of a table starts after the dash line (line 3).
|
|
.SH "What Is a Column Name?"
|
|
.B compute
|
|
looks up, in the column header of the input file,
|
|
each word that it finds in its command-line program.
|
|
If there is a match,
|
|
.B compute
|
|
converts the column name to its position (first, second, third, etc.)
|
|
depending upon the relative location of the column.
|
|
These column numbers are needed by
|
|
.BR awk .
|
|
.PP
|
|
.B compute
|
|
defines a column name to be a string of the following characters:
|
|
.IP \fB1.\fR 0.3i
|
|
Upper and lower letters, numbers, and the underscore `_'.
|
|
.IP \fB2.\fR
|
|
Any string that is enclosed by apostrophes or quotation marks.
|
|
.PP
|
|
Therefore, if you want special characters in your column names,
|
|
put quotation marks around them when you use them.
|
|
For example:
|
|
.DM
|
|
compute ' "Item#" = NR ' < inventory
|
|
.DE
|
|
.PP
|
|
Note the quotation marks around the column head
|
|
.B Item#
|
|
because of the number character `#'.
|
|
Also, note that we used quotation marks,
|
|
because the whole program was enclosed in apostrophes.
|
|
If you use one kind of mark around the whole program,
|
|
use the other kind of mark around the column names
|
|
that have special characters in them.
|
|
.SH "Reserved Words to Avoid in Column Names"
|
|
Some words are understood by
|
|
.BR awk .
|
|
Therefore, they should not be used in column names.
|
|
A simple way to avoid a conflict is to start your column
|
|
names with a capital letter.
|
|
.B awk
|
|
does not confuse
|
|
.B Print
|
|
with
|
|
.BR print .
|
|
Here is a list of
|
|
.BR awk 's
|
|
built-in functions.
|
|
.nf
|
|
.sp \n(pDu
|
|
.ta 1.6i
|
|
\fIReserved Words Description\fR
|
|
.tc .
|
|
\fBBEGIN\fR Pattern that matches before first input record
|
|
\fBEND\fR Pattern that matches after last input record
|
|
\fBbreak\fR Get out of for or while loop
|
|
\fBcontinue\fR Go to next iteration of for or while loop
|
|
\fBelse\fR Used in "if then else" expression
|
|
\fBexit\fR Leave program entirely as if end of input
|
|
\fBexp\fR Raise number to a power
|
|
\fBfor\fR for ( expression ; condition ; expression ) statement
|
|
\fBgetline\fR Get next input line
|
|
\fBif\fR if ( condition ) statement [ else statement ]
|
|
\fBin\fR for ( variable in array ) statement
|
|
\fBindex\fR index ( string1, string2 )
|
|
\fBint\fR Truncate argument to integer
|
|
\fBlength\fR Return current line length, or length of argument
|
|
\fBlog\fR Return log (to base 2) of argument
|
|
\fBnext\fR Skip to next record and reexecute all commands
|
|
\fBprint\fR Output variables
|
|
\fBprintf\fR printf ("format", variable, ... )
|
|
\fBsplit\fR split ( string, arrayname, separator)
|
|
\fBsprintf\fR sprintf ("format", variable, ... )
|
|
\fBsqrt\fR Return square root of argument
|
|
\fBsubstr\fR substr ( string, start, number )
|
|
\fBwhile\fR while ( condition ) statement
|
|
.tc
|
|
.fi
|
|
.SH "Using Shell Variables in Programs"
|
|
Often you want to use a shell variable in a
|
|
.B compute
|
|
command.
|
|
It is easy, if you understand what is going on.
|
|
For example, the following commands:
|
|
.DM
|
|
DATE=860101
|
|
compute "Date = $DATE" < journal
|
|
.DE
|
|
.PP
|
|
produce the following output:
|
|
.DM
|
|
Date Account Debit Credit Description
|
|
------ ------- ----- ------ ----------------------------------
|
|
860101 101 25000 cash from loan
|
|
860101 211.1 25000 loan number #378-14 Bank Amerigold
|
|
860101 150.1 10000 test equipment from Zarkoff
|
|
860101 101 5000 cash payment
|
|
860101 211.2 5000 note payable to Zarkoff Equipment
|
|
860101 130 30000 inventory - parts from CCPSC
|
|
860101 201.1 15000 accounts payable to CCPSC
|
|
860101 101 15000 cash payment to CCPSC for parts
|
|
.DE
|
|
.PP
|
|
We set a shell variable named
|
|
.B DATE
|
|
to a date.
|
|
Then we used the variable in the
|
|
.B compute
|
|
command line program.
|
|
But note that we had to use quotation marks (") instead of our
|
|
usual apostrophes (').
|
|
To the shell, apostrophes protect absolutely.
|
|
With apostrophes, the shell would not see the dollar sign `$' in front of
|
|
.B DATE
|
|
and would not convert it to its value.
|
|
The quotation mark protects the enclosed from the shell, also,
|
|
except for shell variables and command substitution (`cmd`).
|
|
With quotation marks, the shell will still replace variables
|
|
(which start with a dollar sign character).
|
|
.PP
|
|
There is one further complication.
|
|
The previous worked fine because the value of date was a number.
|
|
But if we want to use strings in
|
|
.BR awk ,
|
|
they must have quotation marks (not apostrophes) around them.
|
|
For example:
|
|
.DM
|
|
COMPANY='Makeapile, Inc.'
|
|
compute "Company = \e"$COMPANY\e"" < maillist
|
|
.DE
|
|
.PP
|
|
produces the following:
|
|
.DM
|
|
.ta 1.0i
|
|
Number 1
|
|
Name Ronald McDonald
|
|
Company Makeapile, Inc.
|
|
Street 123 Mac Attack
|
|
City Memphis
|
|
State TENN
|
|
ZIP 30000
|
|
Phone (111) 222-3333
|
|
.DE
|
|
.DM
|
|
.ta 1.0i
|
|
Number 2
|
|
Name Chikeeta Banana
|
|
Company Makeapile, Inc.
|
|
Street Uno Avenito De La Revolution
|
|
City San Jose
|
|
State El Salvadore
|
|
ZIP 123456789
|
|
Phone 1234
|
|
.DE
|
|
.PP
|
|
Here we set a shell variable
|
|
.B COMPANY
|
|
to a company name.
|
|
We want to update the mail list because these characters
|
|
have been hired by a new company.
|
|
Note what we had to do.
|
|
We needed quotation marks around the
|
|
whole program to let the shell substitute the value of the
|
|
shell variable.
|
|
But we also needed quotation marks around
|
|
the string ``Makeapile, Inc.'' for
|
|
.BR awk .
|
|
So we have to protect the innermost quotation marks with backslashes.
|
|
.PP
|
|
There is another way, which opens up a little window in
|
|
the program for the shell to insert strings.
|
|
But it fails when there are spaces in the window string.
|
|
So use the method previously discussed.
|
|
.SH "Problem With awk Floating-Point Format"
|
|
With some implementations of
|
|
.BR awk ,
|
|
the value column is computed to much greater precision
|
|
than you are likely to want.
|
|
For example, version produces this table:
|
|
.DM
|
|
Item# Amount Cost Value Description
|
|
------- ------- ------- ------- ---------------
|
|
1 3 5.00 15 rubber gloves
|
|
2 100 0.50 50 test tubes
|
|
3 5 8.00 40 clamps
|
|
4 23 1.98 45.539997100830078125 plates
|
|
5 99 2.45 242.5499725341796875 cleaning cloth
|
|
6 89 14.75 1312.75 bunsen burners
|
|
7 5 175.00 875 scales
|
|
.DE
|
|
.PP
|
|
To control the precision of the
|
|
floating-point values in a column, you can use the
|
|
.B sprintf
|
|
function from the C programming language that has been implemented in
|
|
.BR awk .
|
|
For example:
|
|
.DM
|
|
compute 'Value = sprintf ("%7.2f", ( Cost * Amount ))' < inventory
|
|
.DE
|
|
.PP
|
|
These commands will produce the first table under Examples, above.
|
|
.SH "Case of Column Names"
|
|
.I "(Ruby re-creation only.)"
|
|
Column names are case sensitive, as in the original
|
|
.BR /rdb .
|
|
If the environment variable
|
|
.B RDB_ICASE
|
|
is set to 1, upper and lower case are ignored when column names are looked up.
|
|
An exact match always wins;
|
|
if several columns differ only in case, the command stops with an
|
|
.I ambiguous
|
|
error.
|
|
Names that are also
|
|
.B awk
|
|
reserved words or are followed by
|
|
.B (
|
|
are never taken for columns.
|
|
.SH "See Also"
|
|
COHERENT Lexicon:
|
|
.B
|
|
awk,
|
|
ksh,
|
|
sh
|
|
.R
|