This is bad code.
getopt is pretty much unusable¹. Use the
getopts shell builtin instead (it has two advantages: it can work, and it's available on all POSIX platforms).
args=$(getopt optstring $*); set -- $args does is:
- Split each command line argument at whitespace and replace it by the list of whitespace-delimited words.
- Take each of the resulting word and interpret it as a wildcard pattern. If the pattern matches at least one file, replace the pattern by the list of matching files.
- Pass the resulting list of words to the
- Store the output of the
getopt command in the variable
args. This is a string consisting of the command line arguments joined together with whitespace as the separator, and reordered to have options and their arguments, then
--, then non-option operands.
- Split this string at whitespace, interpret each word as a wildcard pattern, and replace the pattern by the list of matching files if there are any.
- Use the resulting list as the positional arguments.
In Bourne/POSIX-style shells,
$foo is the “split+glob” operator. You need double quotes to get the value of a variable:
"$foo". But in zsh,
$foo works differently: it expands to the value of
foo except when
foo is empty. So in zsh you get a single positional parameter.
The first use of the split+glob operator could be avoided by writing
getopt optstring "$@": this would pass the positional parameters exactly to
getopt. But when parsing the output of
getopt, splitting is unavoidable (you could disable globbing though), because
getopt uses spaces to separate arguments. The problem with
getopt is that the output is ambiguous: there's no way to distinguish a space that was in an argument from a space that
getopt added as a separator.
The right way to do this is with
getopts. It's robust and portable.
while getopts optstring OPTLET; do
# We got the option -$OPTLET
case $OPTLET in
# Now the positional parameters are just the non-option operands
¹ At least the BSD version. The GNU version adds features that make it usable.