[comp.unix.questions] How read a line of a file from C-shell?

tparker@bierstadt.scd.ucar.edu (Tom Parker) (10/20/90)

I'm having trouble finding a way to read a line of a file in the C-shell.

For instance, I would like my script to read the first line of a file,
process it, then read the second line, process it, etc.

I tried something like      foreach line(`cat file`)
but this seems to process the entire file, a word at a time.

The only method I've gotten to work is this inelegant structure: 

      set line = `head -$n | tail -1`   # Read n-th line

Does anyone have better ways to do file I/O in a C-shell script?

Thanks, Tom

nts0302@dsacg3.dsac.dla.mil (Bob Fisher) (10/22/90)

From article <8900@ncar.ucar.edu>, by tparker@bierstadt.scd.ucar.edu (Tom Parker):
> 
> I'm having trouble finding a way to read a line of a file in the C-shell.
> 
> For instance, I would like my script to read the first line of a file,
> process it, then read the second line, process it, etc.
> 
> I tried something like      foreach line(`cat file`)
> but this seems to process the entire file, a word at a time.

Before doing the "foreach", set the InterField Separator (variable name IFS)
to  a newline character.  The default for IFS is whitespace that includes
blanks.  The default would give you to get one "word" at a time.

When you do this, "line" may include blanks and can sometimes cause syntax
errors because the blanks can be interpreted as separators between command
line arguments.  Example (Bourne syntax):

	IFS='
'			# newline enclosed between single quotes
	for line in `cat file`
	do
	if test $line = ""; then ....

may cause a syntax error in the test command if $line contains whitespace.
However, the statement

	if test "$line" = ""; then ....

will not since the quotes delimit a single argument to the test command.
-- 
Bob Fisher
US Defense Logistics Agency Systems Automation Center
DSAC-TOL, Box 1605, Columbus, OH 43216-5002     614-238-9071 (AV 850-9071)
bfisher@dsac.dla.mil		osu-cis!dsacg1!bfisher

tparker@bierstadt.scd.ucar.edu (Tom Parker) (10/23/90)

Thanks to all those that replied.
 
Several suggested using the C-shell $< function to read the lines from
stdin.  This would work, except that I am submitting my C-shell script as
a job to a remote UNICOS system via NQS, and can't specify a stdin to my
script (the script is the job itself).
 
(By the way, I think that using `line` might be better than $<, since
then you can check for an EOF with $status).
 
One person suggested using 'cat' and setting IFS, but IFS is only in
Bourne shell.
 
The most feasible tip (so far) was to read the file using sed, e.g.:
 
         set lines = `wc -l $file`
 
         while ($i <= $lines[1])
            set line = `sed -n ${i}p $file`
            echo $i $#line $line
            # (Process $line here)
            @ i++
         end
 
This seems to work well, as long as the file doesn't contain any
meta-characters.  (I could put the `sed ...` in double quotes, but then I
can't tokenize the line).
 
Thanks to all that replied,
Tom
 
+---------------------------------------------------------------------------+
|                               Tom Parker                                  |
|                                                                           |
| Consulting Office                         Internet: TPARKER@NCAR.UCAR.EDU |
| Scientific Computing Division             BITNET:   TPARKER@NCARIO        |
| Nat'l Center for Atmospheric Research     Phone:    (303) 497-1227        |
| Boulder, Colorado  80307                                                  |
+---------------------------------------------------------------------------+

itkin@mrspoc.Transact.COM (Steven M. List) (10/25/90)

tparker@bierstadt.scd.ucar.edu (Tom Parker) writes:

>Thanks to all those that replied.
> 
>The most feasible tip (so far) was to read the file using sed, e.g.:
> 
>         set lines = `wc -l $file`
> 
>         while ($i <= $lines[1])
>            set line = `sed -n ${i}p $file`
>            echo $i $#line $line
>            # (Process $line here)
>            @ i++
>         end
> 
>This seems to work well, as long as the file doesn't contain any
>meta-characters.  (I could put the `sed ...` in double quotes, but then I
>can't tokenize the line).

One small optimization:

    set -n "${i}p;${i}q" $file

This will cause sed to STOP when it has printed the line you want.
-- 
 +----------------------------------------------------------------------------+
 :                Steven List @ Transact Software, Inc. :^>~                  :
 :           Chairman, Unify User Group of Northern California                :
 :     {apple,coherent,limbo,mips,pyramid,ubvax}!itkin@guinan.Transact.COM    :

nwosuck@aix.aix.kingston.ibm.com (Kingsley Nwosu) (10/31/90)

In article <8900@ncar.ucar.edu>, tparker@bierstadt.scd.ucar.edu (Tom Parker) writes:
> 
> 
> I tried something like      foreach line(`cat file`)
> 
> The only method I've gotten to work is this inelegant structure: 
> 
>       set line = `head -$n | tail -1`   # Read n-th line
> 
> Does anyone have better ways to do file I/O in a C-shell script?
> 

On my IBM AIX/370 OS I am able to do:

cat <filename> | awk '{FS=CR; print $1}'

This prints each line. You can then pipe the output to the desired function,
if that is what you want.


Kingsley Nwosu			   ...uunet!ibmps2!aix!nwosuck
IBM AIX  Dev., Dept. 83HA/572,  |
Neighborhood Rd, Kingston,      |"Advice to those about to get married: Don't!"
NY 12401.			|	 

kimcm@diku.dk (Kim Christian Madsen) (11/01/90)

nwosuck@aix.aix.kingston.ibm.com (Kingsley Nwosu) writes:

->In article <8900@ncar.ucar.edu>, tparker@bierstadt.scd.ucar.edu (Tom Parker) writes:
->> 
->> 
->> I tried something like      foreach line(`cat file`)
->> 
->> The only method I've gotten to work is this inelegant structure: 
->> 
->>       set line = `head -$n | tail -1`   # Read n-th line
->> 
->> Does anyone have better ways to do file I/O in a C-shell script?
->> 

->On my IBM AIX/370 OS I am able to do:

->cat <filename> | awk '{FS=CR; print $1}'

->This prints each line. You can then pipe the output to the desired function,
->if that is what you want.

If your system is running system V use the command line(1)

otherwise you might want to implement the following code:

----------line.c-----Public Domain Version---------------
#include <stdio.h>

main()
{
	char	line[BUFSIZ];

	fgets(line,BUFSIZ,stdin);
	fputs(line,stdout);
}
----------------------------------------------------------
For more flexibility you can use the following program as well:

--------gets.c------Public Domain Version-----------------
/*
 * gets.c:
 *	Read a line from input and return the read data, if empty return
 *	the default value given as arguments. No interpretation of the
 *	arguments is performed, however it is allowable not to specify
 *	any arguments at all, in which case nothing will be returned.
 *
 * (c) Copyright 1988, Kim Chr. Madsen
 *     All Rights Reserved
 */

#include <stdio.h>

static char *sccsid = "@(#)gets.c	1.1 90/11/01 00:22:43";

main(argc,argv)
int	argc;
char	*argv[];
{
	char	buf[BUFSIZ];
	int	def;

	gets(buf);
	if (strlen(buf)) printf("%s\n",buf);
	else {
		for (def=1; def<argc; def++)
			printf("%s ",argv[def]);
		putchar('\n');
	}
}
--------------------------------------------------------------------

Hope this helps.....

Kim Chr. Madsen

gwc@root.co.uk (Geoff Clare) (11/02/90)

In <1990Oct31.232525.7990@diku.dk> kimcm@diku.dk (Kim Christian Madsen) writes:

>----------line.c-----Public Domain Version---------------
>#include <stdio.h>

>main()
>{
>	char	line[BUFSIZ];

>	fgets(line,BUFSIZ,stdin);
>	fputs(line,stdout);
>}
>----------------------------------------------------------

I was expecting to see a flood of followups pointing out the mistakes
in this implementation of "line".  None have appeared here so far, so
here goes.

The whole point of "line" is that it consumes just the one line of input,
leaving the rest for some other program (or another "line" command) to
read.  The version above, when used to read a regular file, will consume
one block of input, and throw away all but the first line.

It could be made to work correctly by using setvbuf() (if your system has
it) to set stdin to be line buffered, but then you still have the problem
of the line length limit of BUFSIZ bytes.  To cure that you would have to
loop until fgets() returns a buffer with a '\n' on the end.  And I haven't
even mentioned the lack of error checking yet.

There's a long way to go before you have a good quality implementation.
-- 
Geoff Clare <gwc@root.co.uk>  (Dumb American mailers: ...!uunet!root.co.uk!gwc)
UniSoft Limited, Hayne Street, London EC1A 9HH, England.   Tel: +44-71-315-6600

sena@infinet.UUCP (Fred Sena) (11/14/90)

In article <1990Oct31.232525.7990@diku.dk> kimcm@diku.dk (Kim Christian Madsen) writes:


I haven't been on the net for a while, so I'm sorry if this response seems
untimely.

The cleanest way that I have found to get a line of a file is:


set line=`sed -n $n'p' $file`

Where $n is the line number, and $file is the file.


There can be a problem if the line contains *'s though.  Not because of sed,
but because of the way that the csh sets the line variable.  You can't store
a '*' in a csh variable because it wants to turn it into file names.
(Correction, I have yet to find a way)

good luck.
	--fred

--------------------------------------------------
Frederick J. Sena                sena@infinet.UUCP
Memotec Datacom, Inc.  N. Andover, MA
-- 
--------------------------------------------------
Frederick J. Sena                sena@infinet.UUCP
Memotec Datacom, Inc.  N. Andover, MA