[comp.unix.questions] Bourne Shell

jsulliva@cvbnet.UUCP (Jeff Sullivan, x4096 MS 4-2) (03/16/90)

  What is the best way to provide a loop counter in a Bourne
  shell script? An example script is below, all it needs is
  the count incrementer.

      #!/bin/sh
      count=0

      for i in 1 2 3 4 5 6 7 8 9
      do
	# <increment count here>
	echo count=$count
      done

  I know there are other ways to accomplish the same thing,
  (such as the Korn shell), but I'd really like to know how
  to accomplish the above.

  Any help appreciated,
  -Jeff

gwyn@smoke.BRL.MIL (Doug Gwyn) (03/18/90)

i=`expr $i + 1`

jeff@quark.WV.TEK.COM (Jeff Beadles) (03/19/90)

jsulliva@cvbnet.UUCP (Jeff Sullivan, x4096 MS 4-2) writes:

>  What is the best way to provide a loop counter in a Bourne
>  shell script? An example script is below, all it needs is
>  the count incrementer.

>      #!/bin/sh
>      count=0

>      for i in 1 2 3 4 5 6 7 8 9
>      do
>	# <increment count here>
>	echo count=$count
>      done

Well, the easiest way is to use expr.  Ie:

	count=0
	for i in 1 2 3 4 5 6 7 8 9 ; do
		count=`expr $count + 1`
		echo "Count is now $count"
	done

Note, that if you use expr, that special shell characters must be escaped.
This is bad and will cause you pain and suffering:
	count=`expr $count * 2`

This is fine and dandy and will make you a happy camper:
	count=`expr $count \* 2`



	-Jeff
-- 
Jeff Beadles				jeff@quark.WV.TEK.COM 
Utek Engineering, Tektronix Inc.	+1 503 685 2568
			"Credo quia absurdum"

rbottin@atl.calstate.edu (Richard John Botting) (03/19/90)

Jeff <postnews@cvbnetprime.com> Asks
>  What is the best way to provide a loop counter in a Bourne
>  shell script? An example script is below, all it needs is
>  the count incrementer.

>      #!/bin/sh
>      count=0
[...]
>        # <increment count here>
>       echo count=$count
Some people think that this answer is best thought of as a techie joke...
	count=`expr $count + 1`
              ^    ^      ^ ^ ^   
The spaces a VERY significant, as are the reversed quotes. However it works
and is useful in several of scripts.

This is even funnier:
	count=` echo $count|awk '{print $1 + 1}'`

I'd like to see a neat solution (other than a "increment.c" program).

Dick Botting, 
Department of computer science,
California State University, San Bernardino, CA 92407

rbottin@atl.calstate.edu
>INTERNET:rbottin@atl.calstate.edu (Compuserve)
paaaaar@calstate.bitnet 
voice:714-880-5327

brad@SSD.CSD.HARRIS.COM (Brad Appleton) (03/20/90)

In article <124@cvbnetPrime.COM> jsulliva@cvbnet.UUCP (Jeff Sullivan, x4096 MS 4-2) writes:
>
>  What is the best way to provide a loop counter in a Bourne
>  shell script? An example script is below, all it needs is
>  the count incrementer.
>
>      #!/bin/sh
>      count=0
>
>      for i in 1 2 3 4 5 6 7 8 9
>      do
>	# <increment count here>
>	echo count=$count
>      done
>
>  I know there are other ways to accomplish the same thing,
>  (such as the Korn shell), but I'd really like to know how
>  to accomplish the above.
>

First off, I apologize for leaving out the summary in my last post.

Now ...
In the Bourne shell, you can do "arithmetic" with expr. Expr can do 
lots of other stuff too (like pattern matching, and returning portions 
of strings ... read up on it! it is *very* useful).

 Anyway, here is an example:

     $ count=1
     $ count=`expr $count + 1`
     $ echo $count
     2
     $

Hope this helps!

PS - you may want to use a while loop instead of a for loop for your 
     loop counting. Then again, in my experience, "while" is slower.

+=-=-=-=-=-=-=-=-= "... and miles to go before I sleep." -=-=-=-=-=-=-=-=-=-+
|  Brad Appleton                       |  Harris Computer Systems Division  |
|                                      |  2101  West  Cypress  Creek  Road  |
|      brad@ssd.csd.harris.com         |  Fort  Lauderdale, FL  33309  USA  |
|     ... {uunet | novavax}!hcx1!brad  |  MailStop 161      (305) 973-5007  |
+=-=-=-=-=-=-=-=- DISCLAIMER: I said it, not my company! -=-=-=-=-=-=-=-=-=-+

merlyn@iwarp.intel.com (Randal Schwartz) (03/20/90)

In article <22788@adm.BRL.MIL>, rbottin@atl (Richard John Botting) writes:
| I'd like to see a neat solution (other than a "increment.c" program).

If you insist on doing the main looping in sh,

for i in `perl -e '@a=1..20;print"@a";'`
do
	echo $i
done

If you want to just launch stuff quickly,

perl -e 'for $i (1..20) {system "echo $i";}'

Look ma.  No C!

Just another Perl hacker,
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/

tneff@bfmny0.UU.NET (Tom Neff) (03/20/90)

Despite all the neat Perl ways to do it, I consider the little
'count' program an important tool for shell programmers.  You
generally just say

	for i in `count 1 100`

or whatever.  Here it is again:

---- 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:
#	Makefile
#	README
#	count.1
#	count.c
# This archive created: Mon Mar 19 14:15:56 1990
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X#
X# Makefile for count.  This is a little overkill, but what the heck.
X# (This is public domain too!)
X# Written by:  Jeff Beadles
X# jeff@quark.WV.TEK.COM		...tektronix!quark.wv!jeff
X#
X
XCC = cc
XCFLAGS =
X
X#For the executable file
XBINDIR=/usr/bin
X
Xcount: count.c Makefile
X	$(CC) $(CFLAGS) count.c -o count
X
Xinstall: count
X	-strip count
X	cp count ${BINDIR}/count
X	chmod 755 ${BINDIR}/count
X
X	rm -f *.o core a.out
X
Xclobber: clean
X	rm -f count
X
SHAR_EOF
fi
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
X	count -  By:  Jeff Beadles	jeff@quark.WV.TEK.COM
X
X
X	This program will count from the starting number to the stop
X	number, using the character 'fs' as the field seperator.
X
X	Note, that fs may be in several forms:
X	-A	will use the letter 'A'
X	--	will use a '-' as fs, and
X	-\011	will use a tab (Octal 011) as the fs.  (sh does the expansion.)
X
X	Bugs may be sent to me if desired.
X	Please keep your flames to yourself.  What do you expect for free?
SHAR_EOF
fi
if test -f 'count.1'
then
	echo shar: "will not over-write existing file 'count.1'"
else
sed 's/^X//' << \SHAR_EOF > 'count.1'
X.\"
X.\" @(#)count		1.0	05/09/89
X.\"
X.TH COUNT 1 "09 MAY 1989"
X.UC 4
X.SH NAME
Xcount \- count numbers from a start to a stop point.
X.SH SYNOPSIS
X.B count [-c] start stop
X.SH DESCRIPTION
X.I Count
Xwill count thru an integer sequence of numbers from
X.I Start
Xto
X.I Stop
Xwith a newline after each number.
X
XOptionally,
X.I -c
Xmay be on the command line.  This may be in one of two forms.
X.I -$
Xwill put a 
X.I $
Xbetween each number.
X.I -040
Xwill put a space (Octal
X.I 040
X) between each number.
X
X.SH AUTHOR
XJeff Beadles	jeff@quark.WV.TEK.COM
SHAR_EOF
fi
if test -f 'count.c'
then
	echo shar: "will not over-write existing file 'count.c'"
else
sed 's/^X//' << \SHAR_EOF > 'count.c'
X/*	Count.c  Released into the public domain on 05/09/89
X *	Written by:  Jeff Beadles  jeff@quark.WV.TEK.COM
X *	  or ...!tektronix!quark.WV!jeff
X *
X *	NOTE:  This program is not supported by Tektronix, Inc.
X *
X *	This program will count from the starting number to the stop
X *	number, using the character 'fs' as the field seperator.
X *	Note, that fs may be in several forms:
X *	-A	will use the letter 'A'
X *	--	will use a '-' as fs, and
X *	-\011	will use a tab (Octal 011) as the fs.  (sh does the expansion.)
X *
X *	Bugs may be sent to me if desired.
X *	Please keep your flames to yourself.  What do you expect for free?
X *
X */
X
X
X#include <stdio.h>
X#include <ctype.h>
X
X/*
X *	Default field seperator
X */
X
X#ifndef FS
X#define FS '\n'
X#endif
X
Xint
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X
X{
X	void usage();
X	int oatc();
X	int	start = 0;	/* Start count				*/
X	int	stop  = 0;	/* Stop  count				*/
X	int	pos   = 1;	/* Position in command line for parsing	*/
X	char	fs    = FS;	/* Field Separator			*/
X
X	if ( argc < 2)
X		usage(argv[0]);		/* Does not return */
X
X	if ( argv[1][0] == '-' ) {
X		if ( (isdigit(argv[1][1])) && (strlen(argv[1]) == 4) )
X			fs=oatc(argv[1] + 1);
X			else
X			fs = argv[1][1];
X		pos++;		/* On to the next arg... */
X	}
X	start = atoi(argv[pos++]);	/* Start here, and... */
X
X	if ( argc <= pos)
X		usage(argv[0]);		/* Does not return */
X
X	stop  = atoi(argv[pos]); 	/* Stop here. */
X	if ( start >= stop)		/* Are they brain damaged? */
X	{
X		fprintf(stderr,"Error:  START must be less than STOP\n");
X		exit(-2);
X	}
X
X/*
X   Yes, this is it.  It even prints a '\n' when done, if the fs != '\n' (Wow)
X */
X	while ( start <= stop )
X		printf("%d%c",start++,( (start != stop) ? fs : '\n' ) );
X}
X
X/*
X   Can you figure out this function with no comments?  Sure, you can.
X*/
Xvoid usage(program)
Xchar *program;
X
X{
X	fprintf(stderr,"Usage: %s [ -c] start stop\n",program);
X	exit(-1);
X}
X
X/*
X *	octal ascii to char
X */
X
Xint oatc(str)
Xchar *str;
X	{
X	int retval=0;
X	int pos=0;
X	int tmp=0;
X	int loop;
X	static int table[] = { 1, 8, 64 };   /* Powers of 8, to avoid POW */
X
X
X	for(loop=strlen(str) - 1; loop >= 0; loop--)
X		retval += ( (str[loop] - '0') * table[pos++] );
X
X	return((char)retval);
X}
X
SHAR_EOF
fi
exit 0
#	End of shell archive

scott@SRC.Honeywell.COM (Rich Scott) (03/20/90)

In article <22788@adm.BRL.MIL> rbottin@atl.calstate.edu (Richard John Botting) writes:
>Jeff <postnews@cvbnetprime.com> Asks
>>  What is the best way to provide a loop counter in a Bourne
>>  shell script? An example script is below, all it needs is
>>  the count incrementer.
>
>>      #!/bin/sh
>>      count=0
>[...]
>>        # <increment count here>
>>       echo count=$count
> ...
>
> [ points out significant details in using 'expr' ]
> ...
>I'd like to see a neat solution (other than a "increment.c" program).

	Well, in the Korn shell, version 11/16/88 ('ksh88') or later,
you can do:

	for i in 1 2 3 4 5 6 7
        do
                ((count += 1))
                echo count = $count
        done

	
	... which gives you much the same effect. Ksh also has the 'let'
builtin, to evaluate arithmetic expresssions, and so you can do

	let count=count+1

instead, but the double parentheses construct is nice for short expressions, 
since you don't have to worry about spaces.

------------------
rich scott		        		rich@osa.com
open systems architects				scott@src.honeywell.com

brad@SSD.CSD.HARRIS.COM (Brad Appleton) (03/20/90)

In article <22788@adm.BRL.MIL> rbottin@atl.calstate.edu (Richard John Botting) writes:
>Jeff <postnews@cvbnetprime.com> Asks
>>  What is the best way to provide a loop counter in a Bourne
>>  shell script? An example script is below, all it needs is
>>  the count incrementer.
>
>>      #!/bin/sh
>>      count=0
>[...]
>>        # <increment count here>
>>       echo count=$count
> ...
>
> [ points out significant details in using 'expr' ]
> ...
>I'd like to see a neat solution (other than a "increment.c" program).


This is the easiest one yet (using the original example):

        #!/bin/sh
        count=0
	for i in 1 2 3 4 5 6 7 ; do
            count=$i
        done

Has the same effect as incrementing count (and is "plainer" too).
Or better yet:

        #!/bin/sh
        count=7

I guess what Im really asking is:

Why did the asker of the original question need to do the 
incrementing if the for loop was already incrementing a variable 
for him? I think if we knew this we could all provide some assistance 
in helping him find the "nicest" way to do it.

+-=-=-=-=-=-= "... and miles to go before I sleep." -=-=-=-=-=-=-=-=-+
|  Brad Appleton                       |  Harris Corporation         |
|      brad@ssd.csd.harris.com         |  Computer Systems Division  |
|     ... {uunet | novavax}!hcx1!brad  |  Fort Lauderdale, FL  USA   |
+-=-=-=-=-=- DISCLAIMER: I said it, not my company! -=-=-=-=-=-=-=-=-+

pcg@odin.cs.aber.ac.uk (Piercarlo Grandi) (03/21/90)

In article <15270@bfmny0.UU.NET> tneff@bfmny0.UU.NET (Tom Neff) writes:

   Despite all the neat Perl ways to do it, I consider the little
   'count' program an important tool for shell programmers.  You
   generally just say

	   for i in `count 1 100`

   or whatever.  Here it is again:

OK. Sorry to interrupt your regularly scheduled Perl one liners :-), but
I cannot resist a plug. In the 4.2BSd contribs, there was 'jot', that
along with 'rs' and 'lam' is one of the most useful tools I have seen.

'Jot' will generate sequences of numbers, characters, strings, etc...,
with given from, to, step values.

--
Piercarlo "Peter" Grandi           | ARPA: pcg%cs.aber.ac.uk@nsfnet-relay.ac.uk
Dept of CS, UCW Aberystwyth        | UUCP: ...!mcvax!ukc!aber-cs!pcg
Penglais, Aberystwyth SY23 3BZ, UK | INET: pcg@cs.aber.ac.uk

jik@athena.mit.edu (Jonathan I. Kamens) (03/21/90)

  In all this talk about the various ways to count in a shell script,
I'm surprised that no one has mentioned the "jot" program, which I
believes comes standard with BSD nowadays (at least with BSD 4.3 and up
-- I don't know about 4.2).  The first paragraph of the description in
the man page says:

     Jot is used to print out increasing, decreasing, random, or
     redundant data, usually numbers, one per line.

If I wanted a loop to execute 10 times, I would just do "for  i in `jot
10`; do" (or whatever the correct syntax is -- I use csh primarily, so I
don't claim to know the sh syntax off the top of my head :-).

  Alas, it isn't freely redistributable, or at least I assume it isn't,
because it isn't in the bsd-sources archives on uunet.uu.net.

  Somebody could probably rewrite it in perl pretty easily :-)  Hell, it
would even be easy to rewrite from scratch in C.

Jonathan Kamens			              USnail:
MIT Project Athena				11 Ashford Terrace
jik@Athena.MIT.EDU				Allston, MA  02134
Office: 617-253-8495			      Home: 617-782-0710

mercer@ncrcce.StPaul.NCR.COM (Dan Mercer) (03/23/90)

In article <3350@hcx1.SSD.CSD.HARRIS.COM> brad@SSD.CSD.HARRIS.COM (Brad Appleton) writes:
:In article <22788@adm.BRL.MIL> rbottin@atl.calstate.edu (Richard John Botting) writes:
:>Jeff <postnews@cvbnetprime.com> Asks
:>>  What is the best way to provide a loop counter in a Bourne
:>>  shell script? An example script is below, all it needs is
:>>  the count incrementer.
:>
:>>      #!/bin/sh
:>>      count=0
:>[...]
:>>        # <increment count here>
:>>       echo count=$count
:> ...
:>
:> [ points out significant details in using 'expr' ]
:> ...
:>I'd like to see a neat solution (other than a "increment.c" program).
:
:
:This is the easiest one yet (using the original example):
:
:        #!/bin/sh
:        count=0
:	for i in 1 2 3 4 5 6 7 ; do
:            count=$i
:        done
:
:Has the same effect as incrementing count (and is "plainer" too).
:Or better yet:
:
:        #!/bin/sh
:        count=7
:
:I guess what Im really asking is:
:
:Why did the asker of the original question need to do the 
:incrementing if the for loop was already incrementing a variable 
:for him? I think if we knew this we could all provide some assistance 
:in helping him find the "nicest" way to do it.
:
:+-=-=-=-=-=-= "... and miles to go before I sleep." -=-=-=-=-=-=-=-=-+
:|  Brad Appleton                       |  Harris Corporation         |
:|      brad@ssd.csd.harris.com         |  Computer Systems Division  |
:|     ... {uunet | novavax}!hcx1!brad  |  Fort Lauderdale, FL  USA   |
:+-=-=-=-=-=- DISCLAIMER: I said it, not my company! -=-=-=-=-=-=-=-=-+

How prevalent is the BC desk calculator?  We had need not only for
simple addition,  but for more complicated arithmetic and even
hexadecimal computation.  At first,  I just piped the calculations
to BC (which itself is just a front end to DC) and read the response.
However,  this proved to be quite costly in terms of cpu time.  Then I
got a great idea,  starting BC in background and hooking its input and
output to named pipes.  Then,  by sending computations to one FIFO
by echo and reading the response (with either read or line),  I'm
able to do quite complicated computations with low overhead.  Oddly
enough,  even for simple loop counting,  it can completely blow the
pants off an x=`expr ...` solution.
-- 

Dan Mercer
Reply-To: mercer@ncrcce.StPaul.NCR.COM (Dan Mercer)