<p><strong>无应答显示增强的getopt</em>。而且<a href="https://stackoverflow.com/a/14203146/825924">top-voted answer</a>具有误导性:</strong>它要么忽略<code>-vfd</code>样式的短选项(由OP请求),要么忽略位置参数后的选项(也由OP请求);它会忽略解析错误。相反:</p>
<ul>
<li><strong>使用util linux或以前的GNU glibc的增强版<code>getopt</code></strong><sup><sub>1</sub></sup></li>
<li>它与GNU glibc的C函数一起工作</李>
<li><em>本页上没有其他解决方案可以完成所有这一切</em>:
<ul>
<li>在参数<sup><sub>2</sub></sup>中处理空格、引用字符甚至二进制(非增强型<code>getopt</code>无法执行此操作)</li>
<li>它可以在末尾处理选项:<code>script.sh -o outFile file1 file2 -v</code>(<code>getopts</code>不这样做)</li>
<li>允许<code>=</code>样式的长选项:<code>script.sh --outfile=fileOut --infile fileIn</code>(如果自解析,则允许这两个选项都很长)</li>
<li>允许组合短选项,例如<code>-vfd</code>(如果自解析,则实际工作)</li>
<li>允许触摸选项参数,例如<code>-oOutfile</code>或<code>-vfdoOutfile</code></li>
</ul>
</li>
<li>它已经非常古老了<sup><sub>3</sub></sup>,以至于没有任何GNU系统缺少它(例如,任何Linux都有它)</李>
<li>您可以使用:<code>getopt --test</code>测试它是否存在→ 返回值4</李>
<li>其他{<cd2>}或shell内置{<cd6>}的用途有限</李>
</ul>
<p>以下电话</p>
<pre><code>myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile
myscript -v -f -d -o/fizz/someOtherFile -- ./foo/bar/someFile
myscript --verbose --force --debug ./foo/bar/someFile -o/fizz/someOtherFile
myscript --output=/fizz/someOtherFile ./foo/bar/someFile -vfd
myscript ./foo/bar/someFile -df -v --output /fizz/someOtherFile
</code></pre>
<p>全部返回</p>
<pre><code>verbose: y, force: y, debug: y, in: ./foo/bar/someFile, out: /fizz/someOtherFile
</code></pre>
<p>用下面的<code>myscript</code></p>
<pre><code>#!/bin/bash
# More safety, by turning some bugs into errors.
# Without `errexit` you don’t need ! and can replace
# PIPESTATUS with a simple $?, but I don’t do that.
set -o errexit -o pipefail -o noclobber -o nounset
# -allow a command to fail with !’s side effect on errexit
# -use return value from ${PIPESTATUS[0]}, because ! hosed $?
! getopt --test > /dev/null
if [[ ${PIPESTATUS[0]} -ne 4 ]]; then
echo 'I’m sorry, `getopt --test` failed in this environment.'
exit 1
fi
OPTIONS=dfo:v
LONGOPTS=debug,force,output:,verbose
# -regarding ! and PIPESTATUS see above
# -temporarily store output to be able to check for errors
# -activate quoting/enhanced mode (e.g. by writing out “--options”)
# -pass arguments only via -- "$@" to separate them correctly
! PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@")
if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
# e.g. return value is 1
# then getopt has complained about wrong arguments to stdout
exit 2
fi
# read getopt’s output this way to handle the quoting right:
eval set -- "$PARSED"
d=n f=n v=n outFile=-
# now enjoy the options in order and nicely split until we see --
while true; do
case "$1" in
-d|--debug)
d=y
shift
;;
-f|--force)
f=y
shift
;;
-v|--verbose)
v=y
shift
;;
-o|--output)
outFile="$2"
shift 2
;;
--)
shift
break
;;
*)
echo "Programming error"
exit 3
;;
esac
done
# handle non-option arguments
if [[ $# -ne 1 ]]; then
echo "$0: A single input file is required."
exit 4
fi
echo "verbose: $v, force: $f, debug: $d, in: $1, out: $outFile"
</code></pre>
<hr/>
<p><sup><sub>1</sub></sup>增强型getopt可用于大多数“bash系统”,包括Cygwin;在OSX上尝试<a href="https://stackoverflow.com/a/37485578/825924">brew install gnu-getopt</a>或<code>sudo port install getopt</code><br/>
POSIX <code>exec()</code>约定没有可靠的方法在命令行参数中传递二进制NULL;这些字节过早地结束了参数<br/>
<sup><sub>3</sub></sup>1997年或之前发布的第一个版本(我只追溯到1997年)</p>