silvert@dalcs.UUCP (Bill Silvert) (07/25/85)
Here is a reposting of Steve Bourne's field program from his book. I have made a number of enhancements (mainly a changeable field separator) and added an expanded version of his manual entry. Also included are two sample programs, a primitive implementation of finger for those of us without the real thing, and a program to check for changes to the password file (field skips the password itself, so only substantive changes are noted). This is similar to cut, found on Ver. III and V, but can be used to change the order of fields which cut doesn't. I use field a lot on tab-separated data files. -----cut here-----cut here-----cut here-----cut here----- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # field.1L # field.c # finger # checkp # This archive created: Wed Jul 24 07:51:37 1985 # By: Bill Silvert (Marine Ecology Lab, Dartmouth, N. S., Canada) export PATH; PATH=/bin:$PATH if test -f 'field.1L' then echo shar: will not over-write existing file "'field.1L'" else cat << \SHAR_EOF > 'field.1L' .TH FIELD 1L .SH NAME field \- select fields or columns from a file .SH SYNOPSIS .B field [-tc] [-Tc] [ n ] ... .SH DESCRIPTION The .I field command copies selected, delimiter-separated fields from the standard input to the standard output. Fields are numbered from 1 and a field may be requested more than once. .PP The default delimiter is a tab. This can be changed to character .I c with the option -t\c .I c . If the form -T\c .I c is used, the delimiter .I c is used on input, but the output is still separated by tabs. .SH EXAMPLE The following command extracts the login names, user and group numbers from the password file: .PP field -t: 1 3 4 </etc/passwd .SH SEE ALSO .I Cut , which is available on System V. There is a version of .I cut on this system, but no manual entry yet. .SH BUGS The number of input or output fields may not exceed 256 and the maximum line length is 4096 characters. .SH AUTHORS Taken from "The Unix System" by S. R. Bourne. Modifications by William Silvert. SHAR_EOF fi # end of overwriting check if test -f 'field.c' then echo shar: will not over-write existing file "'field.c'" else cat << \SHAR_EOF > 'field.c' /* field utility, from Bourne pp.228-9 */ #include <stdio.h> static char SCCSID[] = "<@(#)field.c 1.11, 85/07/23>"; #define MAXF 256 #define MAXL 4096 #define IFS '\t' /* Field separator is tab on input, */ #define OFS '\t' /* and on output. */ int fv[MAXF]; int nf; int mf; char *fp[MAXF]; char L[MAXL]; main(argc,argv) int argc; char *argv[]; { register char *cp; register char **ap; register int c; int f; char opt, fs, ifs=IFS, ofs=OFS; while (argc>1) { if(sscanf(argv[1], "-%c%c", &opt, &fs) == 2) { switch(opt) { case 't': /* change both field separators */ ofs = fs; case 'T': /* change only ifs */ ifs = fs; break; default: printf("usage: %s [-tc] [ n ] ...\n", argv[0]); return(2); } } else if(sscanf(argv[1], "%d", &fv[nf++]) != 1) { printf("usage: %s [-tc] [ n ] ...\n", argv[0]); return(2); } argc--; argv++; } /* read and copy input */ nf--; cp = L; ap = fp; *ap++ = cp; while(1){ c = getc(stdin); if(c=='\n' || c== EOF) { int fc; if(cp==L && c==EOF) break; *cp++ = 0; mf = ap-fp; /* print this line */ for(fc = 0; fc <= nf; fc++){ putf(fv[fc]-1); if(fc != nf) putchar(ofs); } if(c == EOF) break; putchar('\n'); cp = L; ap = fp; *ap++ = cp; } else if(c == ifs) { *cp++ = 0; *ap++ = cp; } else *cp++ = c; } return(0); } /* output field n from current line */ putf(n) { register char *cp = fp[n]; register char c; if(n<0 || n>=mf) return; while (c = *cp++) putchar(c); } SHAR_EOF fi # end of overwriting check if test -f 'finger' then echo shar: will not over-write existing file "'finger'" else cat << \SHAR_EOF > 'finger' : Silvert variant of finger -- use -a for all info FIELD="field -t: 1 3 4 5 6" case $# in 0) field -T: 1 5 < /etc/passwd ;; *) for i do case $i in -a) FIELD="cat -v" ;; -*) echo "$0: unknown flag $i" ; exit ;; *) grep "^$i:" /etc/passwd | $FIELD ;; esac done ;; esac SHAR_EOF chmod +x 'finger' fi # end of overwriting check if test -f 'checkp' then echo shar: will not over-write existing file "'checkp'" else cat << \SHAR_EOF > 'checkp' #! /bin/sh # check /etc/passwd for changes other than new passwords PATH=/usr/new:/usr/local:/usr/bin:/bin PASSWD=/etc/passwd SECURE=/usr/adm/security STOP=$SECURE/passwd TEMP=/tmp/pass$$ DIFF=/tmp/diff$$ trap '/bin/rm -f $TEMP $DIFF;exit' 0 1 2 3 15 < $PASSWD field -t: 1 3 4 5 6 7 > $TEMP diff $TEMP $STOP > $DIFF if test -s $DIFF then echo "Subject: Changes to /etc/passwd" > $TEMP cat $TEMP $DIFF | mail root exit 1 else exit 0 fi SHAR_EOF chmod +x 'checkp' fi # end of overwriting check # End of shell archive exit 0 -- Bill Silvert Marine Ecology Lab. Dartmouth, NS dalcs!silvert dalcs!biomel!bill