[comp.os.minix] cut

SQ79%liverpool.ac.uk@nsfnet-relay.ac.uk (Mark Powell) (09/14/89)

   Here is an implementation of cut and paste for minix, written by a friend
of mine, who doesn't have USENET access. He has a Pc and I have an ST. It
compiles okay on both machines. Not sure about libraries, but both me and my
friend are using the PC-1.4a libraries.
Enjoy. A very useful program that minix has been missing out on.
Should make shell scripts easier!

Mark Powell

P.S. Yes I know PC1.4a already has paste(1), don't ask me why he wrote his
own!


ARPA sq79%liv.ac.uk@nsfnet-relay.ac.uk
UUCP ...!mcvax!ukc!liv.ac.uk!sq79
----------------------------Cut here------------------------------------
echo x - readme
sed '/^X/s///' > readme << '/'
XHere is cut(1) and paste(1) for MINIX. Cut for those not familiar
Xwith it is a useful little tool used for  stripping  out  columns
Xand fields  from  lines  of  ascii  files.  (particularly  useful
Xfor manipulating  files  such  as  /etc/passwd).  Included  is  a
X(slightly  thrown together) MAN file. Paste being the opposite.
XPlease pass it on and enjoy.
X
XP.S. This is my first addition to the newsgroup and I would  like
Xto hear from anyone who has been developing software specifically
Xfor the AMSTRAD PC      e.g. mouse driver ????
X
XIf anyone is interested I have written fairly fast screen drivers
Xto  support  software  mode  6  (640x200  2  colours).   I   have
Xtwo  drivers,  named /dev/screen0 and 1. When writing to  screen0
Xdata  appears  row  by  row  with  none  of  your  crazy   memory
Xmapping  hassle,  and  when  writting  to  screen1  data  appears
Xcolumn  by  column.  This allows  both  vertical  and  horizontal
Xlines  to  be  written  at  similarly  fast  speeds.  I  am  also
Xworking  on  a  support library.
X
XDoes  anybody  know  anything about  optimum  interleave  factors
Xfor  hard  disks  under  MINIX. Recently I changed the interleave
Xfactor   on   my   Western   Digital   Filecard   (21meg)  (which
Xincidentally runs under MINIX with no  trouble)  from  4  to  10.
XThis  resulted  in  a  near 3 times speed increase under DOS, but
Xshowed  minimal  difference  under  MINIX.  Is  it  possible   to
Xhave  separate  partitions  with  a  different interleave factor?
XIf so where can I get the necessary software to achieve this?
X
XAnyway Hope this is of interest to some of you.
X
XMike Holme.
X
X  I can be contacted via my friends email address
X
X  JANET sq79@uk.ac.liv <Mark Powell>
X  ARPA  sq79%liv.ac.uk@nsfnet-relay.ac.uk
X  UUCP  ...!mcvax!ukc!liv.ac.uk!sq79
X
X  or alternatively tel: 0925 754259
X
X  or 11, Bollin Drive,
X     Lymm,
X     Cheshire.
X     WA13  9QA
X
XCheers.
X---------------------------------cut
here---------------------------------------
/
echo x - cut.c
sed '/^X/s///' > cut.c << '/'
X/* cut - extract columns from a file or stdin. 	Author: Michael J Holme
X *
X *	Copyright 1989, Michael John Holme, All rights reserved.
X *	This code may be freely distributed, provided that this notice
X *	remains intact.
X *
X *	V1.1: 6th September 1989
X *				
X *	Bugs, criticisms, etc,
X *      c/o Mark Powell
X *          JANET sq79@uk.ac.liv
X *          ARPA  sq79%liv.ac.uk@nsfnet-relay.ac.uk
X *          UUCP  ...!mcvax!ukc!liv.ac.uk!sq79
X */
X		
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X
X#define MAX_FIELD	80	/* Pointers to the beginning of each field
X				   are stored in columns[], if a line holds
X				   more than MAX_FIELD columns the array
X				   boundary is exceed. But unlikely at 80 */
Xchar *columns[MAX_FIELD];
X
X#define MAX_ARGS	32	/* Maximum number of fields following
X					   -f or -c switches	  	  */
Xint args[MAX_ARGS*2];
Xint num_args;
X
Xint mode;			/* 0 = dump stdin to stdout, 1=-f, 2=-c   */
Xint flagi;			/* 	     1=-i, 0=no -i 		  */
Xchar delim = '\t';		/* 	default delimiting character	  */
XFILE *fd;
Xchar *name;
Xchar line[BUFSIZ];
Xextern int errno;
X
Xvoid cuterror(err)
Xint err;
X{
Xstatic char *err_mes[] = {
X	"%s: syntax error\n",
X	"%s: position must be >0\n",
X	"%s: unknown option\n",
X	"%s: usage: cut [-f{args} [-i] [-d'x']]|[-c{args}] [filename [...]]\n",
X	"%s: line longer than BUFSIZ\n",
X	"%s: -d option not applicable\n",
X	"%s: -i option not applicable\n",
X	"%s: range must not decrease from left to right\n",
X	"%s: MAX_FIELD exceeded\n",
X	"%s: MAX_ARGS exceeded\n"
X	} ;
X   printf(err_mes[err-1], name);
X   exit(err);
X}
X
X
Xvoid get_args()
X{
Xint i=0;
Xint arg_ptr=0;
Xint flag;
X
X   num_args=0;
X   do
X   {
X      if(num_args==MAX_ARGS) cuterror(10);
X      if(!isdigit(line[i]) && line[i]!='-') cuterror(1);
X
X      args[arg_ptr]=1;
X      args[arg_ptr+1]=BUFSIZ;
X      flag=1;
X
X      while(line[i]!=',' && line[i]!=NULL)
X      {
X         if(isdigit(line[i]))
X         {
X             args[arg_ptr]=0;
X             while(isdigit(line[i]))
X                args[arg_ptr]=10*args[arg_ptr]+line[i++]-'0';
X	     if(!args[arg_ptr]) cuterror(2);
X	     arg_ptr++;
X         }
X         if(line[i]=='-')
X         {
X            arg_ptr|=1;
X	    i++;
X            flag=0;
X         }
X      }
X      if(flag && arg_ptr&1) args[arg_ptr]=args[arg_ptr-1];
X      if(args[num_args*2] > args[num_args*2+1]) cuterror(8);
X      num_args++;
X      arg_ptr=num_args*2;
X   }
X   while(line[i++]);
X}
X
X
Xvoid cut()
X{
Xint i, j, length, maxcol;
X
X   while(fgets(line, BUFSIZ, fd))
X   {
X      length=strlen(line)-1;
X      *(line+length)=NULL;
X      switch(mode)
X      {
X         case 0 : printf("%s", line);
X	          break;
X	 case 1 : maxcol=0;
X		  columns[maxcol++]=line;
X		  for(i=0; i<length; i++)
X		  {
X		     if(*(line+i)==delim)
X		     {
X		        *(line+i)=NULL;
X			if(maxcol==MAX_FIELD) cuterror(9);
X			columns[maxcol]=line+i+1;
X                        while(*(line+i+1)==delim && flagi)
X		        {
X	                   columns[maxcol]++;
X		           i++;
X			}
X                        maxcol++;
X		     }	
X                  }
X		  for(i=0; i<num_args; i++)
X		  {
X		     for(j=args[i*2]; j<=args[i*2+1]; j++)
X			if(j<=maxcol)
X			{
X			   printf("%s", columns[j-1]);
X		           if(i!=num_args-1 || j!=args[i*2+1])
X			      putchar(delim);
X			}
X		  }
X		  break;
X         case 2 : for(i=0; i<num_args; i++)
X                  {
X                     for(j=args[i*2];j<=(args[i*2+1]>length ? length :
args[i*2+1]); j++)
X                        putchar( *(line+j-1) );
X                  }
X      }
X   putchar('\n');
X   }
X}
X
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
Xint flag;
Xint i=1;
X
X   name=argv[0];
X   if(argc==1) cuterror(4);
X
X   while(argv[i] != NULL && argv[i][0] == '-')
X   {
X      switch(argv[i][1])
X      {
X	 case 'd': if(mode==2) cuterror(6);
X		   sprintf(line,"%.1s", &argv[i++][2]);
X		   delim=line[0];
X		   break;
X         case 'f': sprintf(line, "%s", &argv[i++][2]);
X                   mode=1;
X                   get_args();
X                   break;
X	 case 'c': sprintf(line, "%s", &argv[i++][2]);
X		   mode=2;
X		   get_args();
X		   break;
X	 case 'i': if(mode==2) cuterror(7);
X		   flagi=1;
X		   i++;
X		   break;
X	 default : cuterror(3);
X      }
X   }
X
X   if(i < argc)
X      if((fd=fopen(argv[i], "r")) == NULL)
X      {
X         printf("%s: couldn't open %s\n", name, argv[i]);
X	 exit(errno);
X      }
X      else
X      {
X         cut();
X         fclose(fd);
X      }
X   else
X   {
X      fd=stdin;
X      cut();
X   }
X   exit(0);
X}
X
/
echo x - cut.1
sed '/^X/s///' > cut.1 << '/'
XNAME
X    cut(1)      - select fields or columns from line input
X
XSYNOPSIS
X    cut [[-i] [-d'x'] -f{args} [file ...]
X    cut [-c{args}] [file ...]
X
XDESCRIPTION
X    Cut  copies  the  named  ascii files ( or standard input ) to
X    standard  output. In  the  process  of copying, Cut  extracts
X    specified columns. Columns  may  be  specified  by  character
X    positions,   from   1   to  BUFMAX,  or   by  field  numbers.
X    Fields are  groups  of  characters seperated from each  other
X    by the field delimiting character.
X
X    Field and character mode are mutually exclusive and specified
X    by the flags -f{args} and -c{args} respectively.
X
X    {args} takes the form of a comma seperated list of ranges.
X    e.g.   1-5,8-        extract all but 6 and 7.
X           -5            extract the first five.
X           1,3,2         extract   one,   three   and   two   (in
X                         that order).
X
X     -d'x'
X
X     This is used  to  changes  the  field  delimiting  character
X     from the default [tab] to char(x).
X     NOTE: this is only of use with the -f option.
X
X     -i
X
X     Informs cut to ignore null fields ( e.g. consecutive
X     spaces are treated as one )
X     NOTE: again, only of use with -f
X
XEXAMPLES
X
X    $ cut -d: -f1 /etc/passwd
X    root
X    uucp
X    mjh
X    bin
X    daemon
X    msp
X    $ cat >filex
X    Bert Fred Jim
X    Sally Hilary Margaret
X    [CNTL-D]
X    $ cut -d' ' -f2,1 filex
X    Fred Bert
X    Hilary Sally
X    $ for i in `cut -d: -f6 /etc/passwd`
X    > do
X    > echo User `basename $i`: `du -s $i | cut -f1` blocks
X    > done
X    User root: 500 blocks
X    User uucp: 80 blocks
X    etc...
X    $ cut -c-4,-3,-2,1 /etc/passwd
X    rootrooror
X    uucpuucuuu
X    mjh:mjhmjm
X    etc...
X    $
X    ls -al | cut -d' ' -f4 -i
X    1345
X    456
X    32223
X    456
X
XAUTHOR
X    Michael J Holme.
X
XSEE ALSO
X    paste(1)
X
/
echo x - paste.c
sed '/^X/s///' > paste.c << '/'
X/* paste - merge files vertically.	 	Author: Michael J Holme
X *
X *	Copyright 1989, Michael John Holme, All rights reserved.
X *	This code may be freely distributed, provided that this notice
X *	remains intact.
X *
X *	V1.0: 6th September 1989
X *				
X *	Bugs, criticisms, etc,
X *      c/o Mark Powell
X *          JANET sq79@uk.ac.liv
X *          ARPA  sq79%liv.ac.uk@nsfnet-relay.ac.uk
X *          UUCP  ...!mcvax!ukc!liv.ac.uk!sq79
X */
X		
X#include <stdio.h>
X#include <limits.h>
X
Xchar delims[OPEN_MAX+1];
Xchar line[BUFSIZ];
Xchar *name;
Xchar *malloc();
Xint numfiles=0;
Xextern int errno;
XFILE *fd[OPEN_MAX];
X
X
Xvoid pasteerr(err)
Xint err;
X{
Xstatic char *err_mes[] = {
X	"%s: usage: paste [-d\"string\"] file[...]",
X	"%s: unknown option\n",
X	"%s: too many open files\n"
X	} ;
X   printf(err_mes[err-1], name);
X   exit(err);
X}
X
X
Xvoid paste(void)
X{
Xint i, j;
Xint numopen;
X
X   numopen=numfiles;
X   while(numopen)
X   {
X      for(i=0; i<numfiles; i++)
X      {
X 	 if(fd[i])
X     	 {
X            if(fgets(line, BUFSIZ, fd[i]))
X            {
X	       j=strlen(line);
X	       *(line+j-1)=NULL;
X	       printf("%s", line);
X	    }
X	    else
X	    {
X	       fclose(fd[i]);
X	       fd[i]=0;
X	       numopen--;
X            }
X	 if(i!=numfiles-1) putchar(*(delims+i));
X         }
X      }
X   putchar('\n');
X   }
X}
X
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
Xint i, j;
X
X   name=argv[0];
X   if(argc==1) pasteerr(1);
X
X   for(i=0; i<OPEN_MAX; i++) delims[i]='\t';
X
X   i=1;
X   if(argv[i][0] == '-')
X   {
X      switch(argv[i][1])
X      {
X	 case 'd': sprintf(delims,"%OPEN_MAX.s", &argv[i++][2]);
X		   delims[strlen(delims)]='\t';
X		   break;
X         case  0 : fd[numfiles++]=stdin;
X		   i++;
X		   break;
X	 default : pasteerr(2);
X      }
X   }
X
X   while(i < argc)
X   {
X      if(numfiles==OPEN_MAX) pasteerr(3);
X      if((fd[numfiles++]=fopen(argv[i], "r")) == NULL)
X      {
X         printf("%s: couldn't open %s\n", name, argv[i]);
X	 exit(errno);
X      }
X      i++;
X   }
X   paste();
X   exit(0);
X}
X
X
/
echo x - paste.1
sed '/^X/s///' > paste.1 << '/'
XNAME
X    paste(1)      - combine files vertically.
X
XSYNOPSIS
X    cut [-d"string"] [file ...]
X
XDESCRIPTION
X    Paste takes consecutive lines from each specified file and
X    combines them to form one line. The output is via standard
X    output and a tab is  placed  between  each field  one each
X    line. The  -d"string"  switch may be used  to  specify the
X    new field delimiting characters.
X    In fitting with other commands, a minus  sign may  be used
X    in place of a filename to specify  standard input at  that
X    point in the list.
X
XEXAMPLES
X    $ cat >filex
X    Bert
X    Fred
X    Jim
X    cat >filey
X    Sally
X    Hilary
X    Margaret
X    [CNTL-D]
X    $ paste filex filey
X    Bert        Sally
X    Fred        Hilary
X    Jim Margaret
X    $ paste -d":^!" filex filey filex filey
X    Bert:Sally^Bert!Sally
X    Fred:Hilary^Fred!Hilary
X    Jim:Margaret^Jim!Margaret
X
XAUTHOR
X    Michael J Holme.
X
XSEE ALSO
X    cut(1)
X
/
echo x - hogs
sed '/^X/s///' > hogs << '/'
X# hogs: display block usage per user and spot the disk HOGS
X#
X# Written by M.J.Holme
X
Xfor i in `cut -d: -f6 /etc/passwd`
Xdo
X   echo -n User `basename $i`:
X   blocks=`du -s $i | cut -f1`
X   echo -n " $blocks"
X   if ( test 512 -lt $blocks ) ; then
X	echo ' blocks (HOG)'
X   else echo ' blocks'
X   fi
Xdone
/
chmod 755 hogs

fredriks@cbnewse.ATT.COM (lars.fredriksen) (01/13/90)

Hi!
	I tried to extract columns from a file, just as ast tried to do with
cut, but I used the shell. Correct me if I am wrong, but it
would seem to me that the following should work:

	while read COL1 COL2 COL3 ; do
		echo $COL2 $COL3
	done

Let say the script is called "extract", then you could do 

	extract < listing > output

or whatever you want to do..

The only hitch with this scheme is that the shell is broken. The documentation
on the Bourne shell says that read reads a line from stdin, then assigning
the first word to the first variable, second word to the second variable,..
rest of the line to the last variable.
	That means that if the listing file in the above example contained:
	
	011090 45000 cu.c

COL1 should be equal to 011090, COL2 = 45000, and COL3 = cu.c. 

With the minix shell this is what you get:

COL1 = 011090, COL2 = " ", COL3 = 45000. 

We could work around this by using variables for the spaces too. That holds 
true for a file that has the same number of spaces between each column, but 
not if the file looks like the one following:

	011090 4500 cu.c
	011190  500 temp.out
	011290	  0 empty.out

It is even  possible to handle this, but it becomes a mess in a hurry.


Another thing that the shell seems to do wrong(This has probably been 
pointed out already) is the following:

FILES=`/bin/ls *.c`

for i in $FILES ; do
	echo $i
done

The shell varible dosn't have the right format for this to work. If my 
memory server me right, only the last file will be echoed.

I haven't tested this under 1.5.0 yet.


PS. In regards to system V's version of cut; here is an extract from the man
pages:

-d char	The character following -d is the field delimiter (-f option only).
	Default if tab. Space or other characters with special meaning to the
	shell must be quoted.

-flist	The list following -f is a list of fileds assumed to be separated by
	the delimiter character specified by the -d option;e.q., -f1,7 copies

	the first and seventh field only.
	Sincerely
		Lars Fredriksen