rhg@cpsolv.UUCP (Richard H. Gumpertz) (01/05/90)
I recently came across a shell script that, among other things, did the following: OPTIONS= DIRS= for ARG do case "$ARG" in -*) OPTIONS="$OPTIONS $ARG";; *) DIRS="$DIRS $ARG";; esac done if test -z "$DIRS"; then DIRS="." fi set $DIRS find $@ -type f -exec ... where the "..." in the find command indicates irrelevant stuff that I have omitted. My question is, why do the set in the next to last line? Isn't the above roughly equivalent to (but slower than) find $DIRS -type f -exec ... where the set command has been deleted? The only difference I can see is that the version with the set command will make one more passing unquoting things, which could have been avoided using set $DIRS find "$@" -type f -exec ... Are there any other subtle differences that I missed? Is there any way to avoid the one pass of unquoting things that seems to remain in either case? Is there a better way to write this whole thing? (No, perl is not an acceptable alternative in this case; perl scripts will be read but will not solve my problem.) -- ========================================================================== | Richard H. Gumpertz (913) 642-1777 or (816) 891-3561 rhg@CPS.COM | | Computer Problem Solving, 8905 Mohawk Lane, Leawood, Kansas 66206-1749 | ==========================================================================
maart@cs.vu.nl (Maarten Litmaath) (01/09/90)
In article <472@cpsolv.UUCP> rhg@cpsolv.UUCP (Richard H. Gumpertz) writes:
\... set $DIRS
\ find $@ -type f -exec ...
\
\... Isn't the above
\roughly equivalent to (but slower than)
\ find $DIRS -type f -exec ...
\where the set command has been deleted? The only difference I can see is that
\the version with the set command will make one more passing unquoting things,
\which could have been avoided using
\ set $DIRS
\ find "$@" -type f -exec ...
What will happen to an unquoted variable?
1) It is broken up into words at sequences of IFS.
2) It is globbed.
No unquoting.
\Are there any other subtle differences that I missed? Is there any way to
\avoid the one pass of unquoting things that seems to remain in either case?
optc=0
optv=
for i
do
case $i in
-*)
optc=`expr $optc + 1`
eval optv$optc='"$i"'
optv="$optv \"\$optv$optc\""
;;
*)
# you get the idea
esac
done
eval set $optv # restore the options EXACTLY
--
1755 EST, Dec 14, 1992: Henry Spencer is put on a one-way mission to the moon.|
Maarten Litmaath @ VU Amsterdam: maart@cs.vu.nl, uunet!mcsun!botter!maart
gwc@root.co.uk (Geoff Clare) (01/16/90)
In article <5060@solo9.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes: >optc=0 >optv= > >for i >do > case $i in > -*) > optc=`expr $optc + 1` > eval optv$optc='"$i"' > optv="$optv \"\$optv$optc\"" > ;; > *) > # you get the idea > esac >done > >eval set $optv # restore the options EXACTLY A good attempt, Maarten, but there are a couple of big problems here. Firstly, the use of "expr" will be extremely slow for shells which don't have "expr" built in (virtually all Bourne shells, I think). There's no need to use a separate variable for each argument, anyway. Secondly, the final "set" command will not work correctly. Suppose at the start of the script $1 contains "-x". This will end up as a "set -x" command, which will turn on tracing mode in the shell, not place "-x" in $1. With some shells you can use "--" in a "set" command to mark the end of the options, but a dummy first argument is more portable. Try this modified version: optv= for i do case $i in -*) optv="$optv '$i'" ;; *) # you get the idea esac done eval set X "$optv"; shift # restore the options EXACTLY -- Geoff Clare, UniSoft Limited, Saunderson House, Hayne Street, London EC1A 9HH gwc@root.co.uk (Dumb mailers: ...!uunet!root.co.uk!gwc) Tel: +44-1-315-6600
maart@cs.vu.nl (Maarten Litmaath) (01/18/90)
In article <1197@root44.co.uk>, gwc@root.co.uk (Geoff Clare) writes: \In article <5060@solo9.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes: \>optc=0 \>optv= \> \>for i \>do \> case $i in \> -*) \> optc=`expr $optc + 1` \> eval optv$optc='"$i"' \> optv="$optv \"\$optv$optc\"" \> ;; \> *) \> # you get the idea \> esac \>done \> \>eval set $optv # restore the options EXACTLY \ \A good attempt, Maarten, but there are a couple of big problems here. A good attempt, Geoff, but there ... :-) \Firstly, the use of "expr" will be extremely slow for shells which don't \have "expr" built in (virtually all Bourne shells, I think). There's no \need to use a separate variable for each argument, anyway. Wrong. I didn't do that for nothing, you know. See below. \Secondly, the final "set" command will not work correctly. Suppose at \the start of the script $1 contains "-x". This will end up as a \"set -x" command, which will turn on tracing mode in the shell, not \place "-x" in $1. With some shells you can use "--" in a "set" command \to mark the end of the options, but a dummy first argument is more \portable. [...] You're right on this one. In fact I meant to include a `-': eval set - $optv \ case $i in \ -*) \ optv="$optv '$i'" \... What if $i were -' (sic)? Ridiculous, I know, but we're talking foolproof here. The extra level of variables is one way to deal with nasty arguments, here's another: case $i in -*\'*) tmp=`echo x"$i" | sed -e 's/.//' -e "s/'/'\\\\\\\\''/g"` optv="$optv '$tmp'" ;; -*) optv="$optv '$i'" ;; esac BTW, I tested this under SunOS 4.0.3c. But wait a minute! There's another problem: what if $i contains C escape sequences and one is using that terrible System-V echo...? :-( Hmm, one could always use the portable echo hack: ----------8<----------8<----------8<----------8<----------8<---------- : 'portable echo hack: do not interpret backslash escape sequences' cat << EOF $* EOF -- What do the following have in common: access(2), SysV echo, O_NONDELAY? | Maarten Litmaath @ VU Amsterdam: maart@cs.vu.nl, uunet!mcsun!botter!maart