reiner@jabberwock.shs.ohio-state.edu (Reiner Wilhelms) (08/03/90)
I'd like to create a c shell program which reads from 3 files and generates 1 (or more ) output file(s). Calling this csh script will look like this: % my_shell_script input1 input2 input3 output The trouble is, I only know how to read from one file, using the input redirection. I want to read from within that shell script instead of forking a new process, or writing a C-program. Can this be done?? I am working on a sun workstation, SunOS 4.0.3c Thanks in advance. Reiner
tif@doorstop.austin.ibm.com (Paul Chamberlain) (08/04/90)
In article <230@jabberwock.shs.ohio-state.edu> reiner@jabberwock.shs.ohio-state.edu (Reiner Wilhelms) writes: >I'd like to create a c shell program which reads from 3 files and >generates 1 (or more ) output file(s). >Calling this csh script will look like this: > % my_shell_script input1 input2 input3 output 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 think you can use "{" and "}" instead of "(" and ")" to be more efficient (one less process). Paul Chamberlain | I do NOT represent IBM tif@doorstop, sc30661@ausvm6 512/838-7008 | ...!cs.utexas.edu!ibmaus!auschs!doorstop.austin.ibm.com!tif
reiner@slithy-tove.shs.ohio-state.edu (Reiner Wilhelms) (08/08/90)
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@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@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
peter@ficc.ferranti.com (peter da silva) (08/10/90)
(a) The Bourne shell is a *much* better programming tool. Why are you using the C shell for scripts? (b) The "join" command could be used to make a pipeline out of this. #!/bin/sh # If not already sorted: for i in 1 2 3 do sort -d NN.dat$i > NN.sort$i done join -j 1 -o 1.1 1.2 1.3 2.2 2.3 NN.sort1 NN.sort2 | join -j 1 -o 1.1 1.2 1.3 1.4 1.5 2.2 2.3 - NN.sort3 | awk '{print $1"/"$2"/"$3"/"$4"."$5"."$6" "$7}' Appropriate use of /dev/fd could make it even neater, if you don't already have sorted files. -- Peter da Silva. `-_-' +1 713 274 5180. 'U` <peter@ficc.ferranti.com>
guy@auspex.auspex.com (Guy Harris) (08/11/90)
>Appropriate use of /dev/fd could make it even neater, if you don't already >have sorted files. And if you *do* have "/dev/fd", which most UNIX systems at this point don't have, although I think S5R4 might have it.