C-shell programming

Reiner Wilhelms reiner at slithy-tove.shs.ohio-state.edu
Wed Aug 8 07:36:17 AEST 1990


Last week I asked for advise to write a C-shell script which
is capable of reading from more than one file in parallel.
I was lucky: two people (at least) came up with immediate 
answers. Thank you.

Jeffrey Youngstrom (teda!jeffy at decwrl.dec.com ) had this 
piece of code designed for reading one file:
#!/bin/csh -f
# argument 1 ($1) is the input file name
@ line=1
set length=`wc -l $1 | awk '{print $1}'`  # find the number of lines
					  # in the input file
while ($line < $length)
	set stuff=`sed -n $line,${line}p $1`
	# do some stuff
	echo $stuff
	# increment the line count
	@ line++
end
exit

According to him, it is truely slow ("# disgustingly slow csh
cat..."), and he is right. However, I am still very happy that someone
found at least this solution, and it is useful because it can easily be 
extended to reading from several files in the same while loop, see below.

Paul Chamberlain (tif at doorstop.austin.ibm.com)'s important hint 
is for Bourne shells, for which it is also not really obvious
how to read several files in parallel. 

He wrote:
> A bourne shell script could use the 3< 4< etc. syntax like this
> 
>        :
>        (
>        read from_filename1 <&3
>        read from_filename2 <&4
>        read from_filename3 <&5
>        echo to_filename_4 >&6
>        ) 3< $1 4< $2 5< $3 6> $4
>
> I haven't tried this but it's at least close. I don't think
> csh has an equivalent feature...."
>

I agree, as far as I know, there is no real equivalent method
in C-shells. 

With these two hints at hand I tinkered around and finally
arrived at the following two shells which (at least for me)
work. 
The files NN.dat1, NN.dat2, and NN.dat3 contain the lines
printed below. We want to join them into the file 
NN.out, which is also printed below.

::::::::::::::
NN.dat1
::::::::::::::
Joe      32    W 
Terry    40    V
Michel   32    M
Ute      28    K
Reiner   37    G
Uwe      32    D
::::::::::::::
NN.dat2
::::::::::::::
Joe      Chicago  Terry
Terry    Cairo    Michel
Michel   Haiti    Ute
Ute      Berlin   Reiner
Reiner   Columbus Uwe
Uwe      Berlin   NIL
::::::::::::::
NN.dat3
::::::::::::::
Joe      167   ++
Terry    180   *
Michel   177   !!
Ute      180   ??
Reiner   179   +-
Uwe      178   @
::::::::::::::
NN.out (output file)
::::::::::::::
Joe/32/W/Chicago.Terry.167.JJ
Terry/40/V/Cairo.Michel.180.TM
Michel/32/M/Haiti.Ute.177.MT
Ute/28/K/Berlin.Reiner.180.UW
Reiner/37/G/Columbus.Uwe.179.REW
Uwe/32/D/Berlin.NIL.178.UWE
::::::::::::::


Each script is called via 

	% join_shell NN.dat1 NN.dat2 NN.dat3 NN.out

The Bourne-script which does the job is this:

#!/bin/sh
rm -f $4     # remove old output file 
touch $4     # create new one
(
i=0
while read name age code <&3
do
        read namex location follow <&4
        read namex size symbol <&5
        echo $name/$age/$code/$location.$follow.$size $symbol >&6
        i=`expr $i + 1`
done
echo $i lines read
) 3<$1 4<$2 5<$3 6>$4
exit


.. and the csh script which does the same job is here:

#!/bin/csh -f
@ line=1
rm -f $4   # remove old output file
touch $4   # create a new one
set length=`wc -l $1 | awk '{print $1}'`
while ($line <= $length)
        set S=`sed -n ${line}p $1`
        set W=`sed -n ${line}p $2`
        set U=`sed -n ${line}p $3`
        echo $S[1]/$S[2]/$S[3]/$W[2].$W[3].$U[2].$U[3] >> $4
        @ line++
end
echo $length lines read
exit

Both are pretty slow. But I'm glad that they at least work. 
It looks simple, doesn't it. But it takes so much time 
to figure it out, that's why I still hate shell programming.

Reiner



More information about the Comp.unix.questions mailing list