Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!uunet!mcsun!unido!mikros!mwtech!martin From: martin@mwtech.UUCP (Martin Weitzel) Newsgroups: comp.bugs.sys5 Subject: Re: Shell Scripts v. Command Options Message-ID: <1083@mwtech.UUCP> Date: 3 Feb 91 13:32:53 GMT References: <18899@rpp386.cactus.org> <1991Jan14.202053.20054@zoo.toronto.edu> <18946@rpp386.cactus.org> <1991Jan16.175908.3338@zoo.toronto Reply-To: martin@mwtech.UUCP (Martin Weitzel) Organization: MIKROS Systemware, Darmstadt/W-Germany Lines: 91 In article <18964@rpp386.cactus.org> jfh@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@mwtech.UUCP, voice: 49-(0)6151-6 56 83