[Most of this article, except IFS and --, also applies to the C shell. -- JP]
You can pass options and arguments to a shell as you start it, as in:
sh -v file1 file2
and also when a script is invoked with #!. The set command lets you set command-line parameters, including most[112] shell options, after you've started the shell. This simple idea has more uses than you might realize.
[112]Some options for some shells can be set only from the command line as the shell is invoked. Check the shell's manual page.
The Bourne shell command line can have options like -e (exit if any command returns nonzero status). It can also have other arguments; these are passed to shell scripts. You can set new command-line parameters while you're typing interactive commands (at a shell prompt) or in a shell script.
To reset the command-line parameters, just type set followed by the new parameters. For example, to ask the shell to show expanded versions of command lines after you type them, set the -v (verbose) option (Section 27.15):
$ set -v $ mail $group1 < message mail andy ellen heather steve wilma < message $ mail $group2 < message mail jpeek@jpeek.com randy@xyz.edu yori@mongo.medfly.com < message $ set +v
On many Bourne shells, typing set +v cancels the v option. On other (mostly early) shells, there's no + feature. To work around that problem, you could start a subshell (Section 24.4) with sh -v, run the commands there, then exit the subshell to cancel the verbose option.
Go to http://examples.oreilly.com/upt3 for more information on: users
You can put filenames or any other strings in the command-line parameters interactively or from a shell script. That's handy for storing and parsing the output of a Unix command with backquotes (Section 28.14). For example, you can get a list of all logged-in users from the parameters $1, $2, and so on. Use users (or rusers to find all the logged in users on the local network) if your system has it. Otherwise, use who (Section 2.8) and cut (Section 21.14) to strip off everything but the usernames:
for Section 35.21
$ set `users` $ set `who | cut -c1-8` $ for u > do > ...do something with each user ($u)... > done
You can save the original parameters in another variable and reset them later:
oldparms="$*" set something new ...use new settings... set $oldparms
Be sure to watch your quoting (as the next section explains).
If the first parameter you set starts with a dash, like -e, the shell will treat it as its own option instead of as a string to put into the command-line parameters. To avoid this, use -- (two dashes) as the first argument to set. In this example, $1 gets -e, and the filenames expanded from the wildcard pattern go into $2, $3, etc.:
set -- -e file*
If you type set by itself with no arguments, it will show a list of all currently set shell variables. In newer Bourne-type shells, it also shows shell functions (Section 29.11) and other shell settings.
This can cause you grief if you accidentally don't pass arguments to set in the middle of a script, and screenfuls of variables spew onto the user's screen. For example, your script runs set 'users' from a cron (Section 25.2) job, in the middle of the night when no one is logged on. The users command returns an empty string, so set gets no arguments, so it outputs a long list of junk.
The standard workaround for this problem is to always use a dummy first parameter -- typically, a single x -- when you're setting parameters. Then use shift (Section 35.22) to shift away the x, leaving the other parameters (possibly none). For example:
set x `users` shift
Because the shell parses and scans the new parameters before it stores them, wildcards (Section 33.2) and other special characters (Section 27.17) will be interpreted, so watch your quoting (Section 27.12). You can take advantage of this to parse lines of text into pieces that aren't separated with the usual spaces and TABs -- for instance, a line from a database with colon-separated fields -- by setting the IFS (Section 36.23) variable before the set command.
If you want to save any special quoting on the original command line, be careful: the quoting will be lost unless you're clever. For example, if $1 used to be John Smith, it will be split after it's restored: $1 will have John and $2 will be Smith. A better solution might be to use a subshell (Section 43.7) for the part of the script where you need to reset the command-line parameters:
# reset command-line parameters during subshell only: (set some new parameters ...do something with new parameters... ) # original parameters aren't affected from here on...
One last note: set won't set $0, the name of the script file.
-- JP
Copyright © 2003 O'Reilly & Associates. All rights reserved.