Shell Scripts v. Command Options

Martin Weitzel martin at mwtech.UUCP
Mon Feb 4 00:32:53 AEST 1991


In article <18964 at rpp386.cactus.org> jfh at rpp386.cactus.org (John F Haugh II) writes:
[...]
>There are some obvious places where scripts are warranted - such as where
>the execution time of the commands being executed dominates the execution
>time of the shell.  In the case of short lived commands, such as "who |
>wc -l" it may be questionable - the command doesn't run very long in
>either case.  A more ridiculous example might be where "who -q" is
>implemented somewhat faithfully as a shell script.
             ^^^^^^^^^^^^^^^^^^^ (Hmm, as English is not my native language
I'm not quite sure but I suppose this means the following example was
deliberatly choosen not to show good performance - i.e. the poster is
aware of the complicated way the script does its work.)

>if [ $# != 0 ]; then
>	INPUT=$1
>else
>	INPUT=/etc/utmp
>fi
>USERS=`who $INPUT | cut -d' ' -f1`
>LINE=0
>for USER in $USERS; do
>	LENGTH=`expr $USER : '.*'`
>	if [ `expr $LENGTH + $LINE + 1` -gt 80 ]; then
>		LINE=0
>		echo
>	fi
>	LINE=`expr $LINE + $LENGTH + 1`
>	echo $USER '\c'
>done
>echo
>COUNT=`who $INPUT | wc -l | sed -e 's/ *//g'`
>echo '# users='$COUNT

IMHO one problem is - as shown here - that often programming techniques
useful in other languages are simply transliterated into the shell. The
experienced shell programmer will generally try to avoid `expr ...` (and
if he or she allready programmed under V7 also `test ...`), especially
in the body of some often executed loop.

An improvement to the above script avoids two `expr ....` within the
body of the loop and reduces usr-time to 40% and sys-time to 30% of the
original example (timings are taken on my 386-box and I'm aware of the
difficulties timing a shell script containing pipes; as the most complex
part is at the end of the pipe this shouldn't matter too much).

case $# in
0) INPUT=/etc/utmp;;
1) INPUT=$1;;
esac
NL=''
who $INPUT |
pr -tn | (
	while read num usr rest
	do
		if [ `expr "$OUTLINE$usr " : '.*'` -gt 80 ]
		then
			echo "$NL$OUTLINE"'\c'
			NL='\n'
			OUTLINE="$usr "
		else
			OUTLINE="$OUTLINE$usr "
		fi
		count=$num
	done
	echo "$NL$OUTLINE"
	echo "# users=$count"
)

I think the above algorithm is not less obvious than the original example.
The remaining `expr ...` in the body of the loop could also be changed into

	case "$OUTLINE$usr"
	????????<80 question marks total>?????????*)
		echo "$NL$OUTLINE"'\c'
		NL='\n'
		OUTLINE="$usr "
		;;
	*)
		OUTLINE="$OUTLINE$usr "
		;;
	esac

but I'd only choose that if I were hunting for performance, because it
looks a bit obscure. (BTW: This last optmization reduces usr-time to
25% and sys-time to 5% of the original example.)

Conclusion: Most languages have more and less efficient ways to do one
and the same thing. Doing it the way you achieve good performance in
one language may not fit well to some other language and vice versa.
-- 
Martin Weitzel, email: martin at mwtech.UUCP, voice: 49-(0)6151-6 56 83



More information about the Comp.bugs.sys5 mailing list