From owner-freebsd-questions@FreeBSD.ORG Sun Jun 6 09:09:31 2010 Return-Path: Delivered-To: questions@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id E0C79106564A for ; Sun, 6 Jun 2010 09:09:31 +0000 (UTC) (envelope-from m.seaman@infracaninophile.co.uk) Received: from smtp.infracaninophile.co.uk (gate6.infracaninophile.co.uk [IPv6:2001:8b0:151:1::1]) by mx1.freebsd.org (Postfix) with ESMTP id 5BB4F8FC1A for ; Sun, 6 Jun 2010 09:09:31 +0000 (UTC) Received: from seedling.black-earth.co.uk (seedling.black-earth.co.uk [81.187.76.163]) (authenticated bits=0) by smtp.infracaninophile.co.uk (8.14.4/8.14.4) with ESMTP id o5699Llx079158 (version=TLSv1/SSLv3 cipher=DHE-RSA-CAMELLIA256-SHA bits=256 verify=NO); Sun, 6 Jun 2010 10:09:22 +0100 (BST) (envelope-from m.seaman@infracaninophile.co.uk) Message-ID: <4C0B65C1.8030003@infracaninophile.co.uk> Date: Sun, 06 Jun 2010 10:09:21 +0100 From: Matthew Seaman Organization: Infracaninophile User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.9) Gecko/20100317 Thunderbird/3.0.4 MIME-Version: 1.0 To: Aiza References: <201006051513.o55FDCKj020952@mail.r-bonomi.com> <4C0ADBCF.8040506@comclark.com> <20100606014737.GG85961@dan.emsphone.com> <4C0B1C61.9030501@comclark.com> <4C0B26B5.3090901@cyberleo.net> <4C0B2AC1.1080805@comclark.com> <4C0B4A51.20402@infracaninophile.co.uk> <4C0B5108.2080903@comclark.com> In-Reply-To: <4C0B5108.2080903@comclark.com> X-Enigmail-Version: 1.0.1 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Virus-Scanned: clamav-milter 0.96.1 at lucid-nonsense.infracaninophile.co.uk X-Virus-Status: Clean X-Spam-Status: No, score=1.6 required=5.0 tests=BAYES_50,DKIM_ADSP_ALL, SPF_FAIL autolearn=no version=3.3.1 X-Spam-Level: * X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on lucid-nonsense.infracaninophile.co.uk Cc: "questions@freebsd.org" Subject: Re: .sh & getopts X-BeenThere: freebsd-questions@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: User questions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 06 Jun 2010 09:09:32 -0000 -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 06/06/2010 08:40:56, Aiza wrote: > I have been looking for documentation on freebsd's sh shell programming. > Want to understand what is happening in that getopts I posted. Where can > I find real explanations? Well, the essential reference is the sh(1) man page. Just about everything you could need to know is in there, but possibly not in a way that you would find particularly accessible for deconstructing a piece of arbitrary code. In this sort of case, probably your best bet is to ask for advice. While such questions are verging on off-topic for this list they do seem to come up with reasonable frequency and usually receive pretty good answers. Let's see... You mean this, I take it: shift; while getopts :ugr: arg; do case ${arg} in u) action="freebsd-update";; g) action="freebsd-upgrade";; r) action="freebsd-rollback";; ?) exerr ${cmd_usage};; esac; done; shift $(( ${OPTION} -1 )) Let me reformat that a bit so it's clearer, and add some line numbers: 01: shift 02: while getopts :ugr: arg 03: do 04: case ${arg} in 05: u) 06: action="freebsd-update" 07: ;; 08: g) 09: action="freebsd-upgrade" 10: ;; 11; r) 12: action="freebsd-rollback" 13: ;; 14: ?) 15: exerr ${cmd_usage} 16: ;; 17: esac 18: done 19: shift $(( ${OPTION} -1 )) So, line 01 discards the first item from the argument list -- that's just the program name. (The argument list is available as $@ -- which is somewhat special cased, in that it acts as an array, which is otherwise not a type provided by posix sh(1)) Actually, I don't think you need to do this -- getopts is clever enough to deal with that itself. The while loop from lines 02 to 18 invokes getopts to process the argument list. getopts is a sh(1) built-in, but it behaves as if it is an external program. It takes two arguments: the list of option specifiers, and the variable name to set to the current arg being processed. Your option string indicates that you expect to deal with -u -g -r foo bar (ie. a bare argument with no option letter) (Not actually sure if the bare argument thing actually works. Usually, you use getopts to process all of the option flags, then a separate bit of code to deal with anything else left in $@) Now, inside the while loop, you just have a case statement so you can jump to the appropriate code for handling each different option. Hmmm... except you don't handle the bare argument case, nor do you do anything with the argument to the '-r' option -- you should copy the value of $OPTARG somewhere to save for later processing within that part of the case statement. Now, the enclosing while loop will process all of the command line options and as you (re)set the 'action' variable each time, only the last named of and -u, -g or -r options will be effective. That's reasonable given that the available options seem to be mutually exclusive. Maybe emitting a warning if you reset the action variable would be a good idea. One way of doing that is this construct: [ -z ${action} ] || echo "Warning -- action multiply specified" You can add that between lines 03 and 04. Finally, at line 19, you attempt to discard presumably all of the options from $@ that getopts has already processed. Unfortunately, $OPTION is (I think) a bash-ism, and not available with the getopts in FreeBSD sh(1). Instead, you should be looking at $OPTIND. Like so: shift $(($OPTIND - 1)) All in all, this is pretty much the normal shell code idiom for handling command line options. After running this, you should be left with $@ containing just those arguments /not/ preceded by option flags. Cheers, Matthew - -- Dr Matthew J Seaman MA, D.Phil. 7 Priory Courtyard Flat 3 PGP: http://www.infracaninophile.co.uk/pgpkey Ramsgate JID: matthew@infracaninophile.co.uk Kent, CT11 9PW -----BEGIN PGP SIGNATURE----- Version: GnuPG/MacGPG2 v2.0.14 (Darwin) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkwLZcAACgkQ8Mjk52CukIzZ3QCeN3SnzJa70/ixOXWQxuz777WW 36MAmgPmPHZnrZw4BoqVZ13U+NopA5HX =Qoc7 -----END PGP SIGNATURE-----