It is a sad fact that the UNIX shell is not a high level programming language--consequently, effective shell coding often involves arcane tricks. In this section, we'll provide some useful templates for some of the common UNIX shell programming idioms.
We use CvStack as an illustration. The core of this shell is a double loop over velocities and cdps that produces velocity panels--a concept not contained in any single SU program.
Remark: For most of us, writing a shell like CvStack from scratch is a time-consuming affair. To cut down the development time, your authors excerpt from existing shells to make new ones even when we don't quite remember what every detail means. We suggest that you do the same!
We won't comment on the lines already explained in our previous two shell code examples (see Sections 8.2.1 and 8.2.3), but instead focus on the new features used in CvStack.
#! /bin/sh # Constant-velocity stack of a range of cmp gathers # Authors: Jack, Ken # NOTE: Comment lines preceding user input start with #!# set -x #!# Set input/output file names and data parameters input=cdp601to610 stackdata=cvstack cdpmin=601 cdpmax=610 fold=30 space=1 # 1 null trace between panels #!# Determine velocity sampling. vmin=1500 vmax=3000 dv=150 ### Determine ns and dt from data (for sunull) nt=`sugethw ns <$input | sed 1q | sed 's/.*ns=//'`  dt=`sugethw dt <$input | sed 1q | sed 's/.*dt=//'` ### Convert dt to seconds from header value in microseconds dt=`bc -l <<END  scale=4 $dt / 1000000 END` ### Do the velocity analyses. >$stackdata # zero output file  v=$vmin while [ $v -le $vmax ]  do cdp=$cdpmin while [ $cdp -le $cdpmax ]  do suwind <$input \  key=cdp min=$cdp max=$cdp count=$fold | sunmo cdp=$cdp vnmo=$v tnmo=0.0 | sustack >>$stackdata cdp=`bc -l <<END  $cdp + 1 END` done sunull ntr=$space nt=$nt dt=$dt >>$stackdata  v=`bc -l <<END $v + $dv END` done ### Plot the common velocity stacked data ncdp=`bc -l <<END $cdpmax-$cdpmin+1 END` f2=$vmin d2=`bc -l <<END $dv/($ncdp + $space)  END` sugain <$stackdata tpow=2.0 | suximage perc=99 f2=$f2 d2=$d2 \ title="File: $input Constant-Velocity Stack " \ label1="Time (s)" label2="Velocity (m/s)" & exit Discussion of numbered lines:
% suplane | sugethw tracl ns tracl=1 ns=64 tracl=2 ns=64 tracl=3 ns=64 tracl=4 ns=64 tracl=5 ns=64 tracl=6 ns=64 ...Although sugethw is eager to give the values for every trace in the data set, we only need it once. The solution is to use the UNIX stream editor (sed). In fact, we use it twice. By default, sed passes along its input to its output. Our first use is merely to tell sed to quit after it puts the first line in the pipe. The second pass through sed strips off the unwanted material before the integer. In detail, the second sed command reads: replace (or substitute) everything up to the characters
ns=with nothing, i.e., delete those characters.
dt. The calculation may take several lines. We first set the number of decimal places with
scale=4and then do the conversion to seconds. The characters
ENDthat follow the here document redirection symbol
<<are arbitrary, the shell takes its input from the text in the shell file until it comes to a line that contains the same characters again. For more information about bc:
% man bc
>always does as its first action--it's a dangerous operator! If you intend to append, then, as mentioned earlier, use
Caveat: The bracket notation is a nice
alternative to the older clunky
while test $v -le $vmaxBecause the bracket notation is not documented on the typical sh manual page, we have some qualms about using it. But, as far as we know, all modern sh commands support it--please let us know if you find one that doesn't.
WARNING! OK, now you know that there is a UNIX command
test. So don't use the name ``test'' for one of your
shell (or C) programs--depending on your
$PATH setting, you could
be faced with seemingly inexplicable output.
ENDagainst the left margin. That's because the sh manual page says that the termination should contain only the
END(or whatever you use). In fact, most versions support indentation. We didn't think the added beautification was worth the risk in a shell meant for export. Also note that we used bc for an integer arithmetic calculation even though integer arithmetic is built into the Bourne shell--why learn two arcane rituals, when one will do? See
man expr, if you are curious.
CvStack. Actually, I had written this program many times, but this was the first time I did it on purpose. (Yes, that was an attempt at humor.)
exitstatement is useful because you might want to save some ``spare parts'' for future use. If so, just put them after the
exitstatement and they won't be executed.
Figure 8.2 shows an output generated by