shell 脚本的跨平台 getopt

发布于 2024-08-30 09:51:12 字数 77 浏览 8 评论 0原文

我刚刚发现 getopt 不是跨平台的(特别是对于 FreeBSD 和 Linux)。此问题的最佳解决方法是什么?

I've just found out that getopt is not cross-platform (in particular for FreeBSD and Linux). What is the best workaround for this issue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

辞别 2024-09-06 09:51:12

getopt 命令本质上有两个版本:原始版本和 GNU 增强版本。 GNU 增强版向后兼容原始版本,因此如果您只使用原始版本的功能,那么两者都可以使用。

检测 getopt 的可用版本

您可以检测哪个版本可用,如果 GNU 增强版可用,则使用增强功能;如果 GNU 增强版不可用,则限制自己使用原始功能。增强版有一个-T选项用于测试哪个版本可用。

getopt -T > /dev/null
if [ $? -eq 4 ]; then
    # GNU enhanced getopt is available
    set -- `getopt --long help,output:,version --options ho:v -- "$@"`
else
    # Original getopt is available
    set -- `getopt ho:v "$@"`
fi

考虑使用内置 shell 命令 getopts (带有“s”),因为它更便携。但是,getopts 不支持长选项(例如--help)。

如果您喜欢长选项,请使用getopt并使用上面的测试来查看getopt的GNU增强版本是否可用。如果增强版本不可用,脚本可以正常降级为使用 getopt 的原始版本(不支持长选项名称,也不支持空格)或使用 getopts > (不支持长选项名称)。

正确使用 GNU 增强的 getopt

让 GNU 增强版本正确处理带有空格的参数是很棘手的。其实现方式如下:

ARGS=`getopt --long help,output:,verbose --options ho:v -- "$@"`
if [ $? -ne 0 ]; then
  echo "Usage error (use -h for help)" >&2
  exit 2
fi
eval set -- $ARGS

# Parameters are now sorted: options appear first, followed by --, then arguments
# e.g. entering: "foo bar" -o abc baz -v
#      produces: -o 'abc' -v -- 'foo bar' 'baz'

秘诀是使用 "$@",其中双引号非常重要(在第 1 行中),并eval 设置 命令(第 6 行)。

因此,可以检测和处理 getopt 引发的错误,对 getopt 的调用与 eval 分开进行,两者通过 ARGS 变量链接。

完整的工作示例

PROG=`basename $0`

getopt -T > /dev/null
if [ $? -eq 4 ]; then
  # GNU enhanced getopt is available
  ARGS=`getopt --name "$PROG" --long help,output:,verbose --options ho:v -- "$@"`
else
  # Original getopt is available (no long option names, no whitespace, no sorting)
  ARGS=`getopt ho:v "$@"`
fi
if [ $? -ne 0 ]; then
  echo "$PROG: usage error (use -h for help)" >&2
  exit 2
fi
eval set -- $ARGS

while [ $# -gt 0 ]; do
    case "$1" in
        -h | --help)     HELP=yes;;
        -o | --output)   OUTFILE="$2"; shift;;
        -v | --verbose)  VERBOSE=yes;;
        --)              shift; break;; # end of options
    esac
    shift
done

if [ $# -gt 0 ]; then
  # Remaining parameters can be processed
  for ARG in "$@"; do
    echo "$PROG: argument: $ARG"
  done
fi

echo "$PROG: verbose: $VERBOSE"
echo "$PROG: output: $OUTFILE"
echo "$PROG: help: $HELP"

该示例可以从 https://gist.github.com 下载/hoylen/6607180

维基百科关于 getopts 的条目上的比较表比较了不同的功能。

There are essentially two versions of the getopt command: the original version and the GNU enhanced version. The GNU enhanced version is backward compatible with the original version, so if you only use the features of the original version it will work with both.

Detect which version of getopt is available

You can detect which version is available and use the enhanced features if the GNU enhanced version is available, and limit yourself to the original features if the GNU enhanced version is not available. The enhanced version has a -T option for testing which version is available.

getopt -T > /dev/null
if [ $? -eq 4 ]; then
    # GNU enhanced getopt is available
    set -- `getopt --long help,output:,version --options ho:v -- "$@"`
else
    # Original getopt is available
    set -- `getopt ho:v "$@"`
fi

Consider using built-in shell command getopts (with an "s") instead, because it is more portable. However, getopts does not support long options (e.g. --help).

If you like long options, use getopt and use the above test to see if the GNU enhanced version of getopt is available or not. If the enhanced version is not available, the script can gracefully degrade to either using the original version of getopt (with no support for long option names and no whitespace support) or using getopts (with no support for long option names).

Using GNU enhanced getopt properly

Getting the GNU enhanced version to process arguments with whitespace properly is tricky. Here's how it is done:

ARGS=`getopt --long help,output:,verbose --options ho:v -- "$@"`
if [ $? -ne 0 ]; then
  echo "Usage error (use -h for help)" >&2
  exit 2
fi
eval set -- $ARGS

# Parameters are now sorted: options appear first, followed by --, then arguments
# e.g. entering: "foo bar" -o abc baz -v
#      produces: -o 'abc' -v -- 'foo bar' 'baz'

The secret is to use "$@" where the double quotes are very important (in line 1), and to eval the set command (in line 6).

So errors raised by getopt can be detected and handled, the call to getopt is done separately from the eval with the two linked by the ARGS variable.

Complete working example

PROG=`basename $0`

getopt -T > /dev/null
if [ $? -eq 4 ]; then
  # GNU enhanced getopt is available
  ARGS=`getopt --name "$PROG" --long help,output:,verbose --options ho:v -- "$@"`
else
  # Original getopt is available (no long option names, no whitespace, no sorting)
  ARGS=`getopt ho:v "$@"`
fi
if [ $? -ne 0 ]; then
  echo "$PROG: usage error (use -h for help)" >&2
  exit 2
fi
eval set -- $ARGS

while [ $# -gt 0 ]; do
    case "$1" in
        -h | --help)     HELP=yes;;
        -o | --output)   OUTFILE="$2"; shift;;
        -v | --verbose)  VERBOSE=yes;;
        --)              shift; break;; # end of options
    esac
    shift
done

if [ $# -gt 0 ]; then
  # Remaining parameters can be processed
  for ARG in "$@"; do
    echo "$PROG: argument: $ARG"
  done
fi

echo "$PROG: verbose: $VERBOSE"
echo "$PROG: output: $OUTFILE"
echo "$PROG: help: $HELP"

This example can be downloaded from https://gist.github.com/hoylen/6607180

The comparison table on Wikipedia's entry on getopts compares the different features.

咽泪装欢 2024-09-06 09:51:12

使用getopts(带有“s”)。

根据 Bash 常见问题解答 35

除非它是 util-linux 的版本,并且您使用其高级模式,否则切勿使用 getopt(1)。 getopt 无法处理空参数字符串或嵌入空格的参数。请忘记它曾经存在过。

POSIX shell(和其他)提供了可以安全使用的 getopts。

Use getopts (with an "s").

According to Bash FAQ 35:

Unless it's the version from util-linux, and you use its advanced mode, never use getopt(1). getopt cannot handle empty arguments strings, or arguments with embedded whitespace. Please forget that it ever existed.

The POSIX shell (and others) offer getopts which is safe to use instead.

在风中等你 2024-09-06 09:51:12

getopt 的基本语法是跨平台的。

getopt vi: -v -i 100 file

Basic syntax for getopt is cross-platform.

getopt vi: -v -i 100 file
愿得七秒忆 2024-09-06 09:51:12

Bash 内置 getopts 函数可用于可移植地解析短选项和长选项,请参阅:

在 bash shell 脚本中使用 getopts 获取长和短命令行选项

The Bash builtin getopts function can be used to parse short and long options portably, see:

Using getopts in bash shell script to get long and short command line options

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文