如何创建接受参数的bash脚本?

如何创建接受参数的bash脚本?,bash,Bash,我已经知道了getopts,这很好,但即使对于强制参数,也必须有一个标志,这很烦人 理想情况下,我希望能够有一个脚本来接收以下形式的参数: script.sh [optional arguments] [anything required] 比如说 script.sh -rvx output_file.txt 脚本说你必须有一个输出文件。有什么简单的方法可以做到这一点吗 据我所知,使用getopts时,它必须看起来像:script.sh-rvx-f output_file.txt,但这不是很

我已经知道了getopts,这很好,但即使对于强制参数,也必须有一个标志,这很烦人

理想情况下,我希望能够有一个脚本来接收以下形式的参数:

script.sh [optional arguments] [anything required]
比如说

script.sh -rvx output_file.txt
脚本说你必须有一个输出文件。有什么简单的方法可以做到这一点吗

据我所知,使用getopts时,它必须看起来像:
script.sh-rvx-f output_file.txt
,但这不是很干净


如果需要,我也可以使用python,但只有2.4版可用,这有点过时。

不要使用getopts内置,而是使用getopt(1)。他们(微妙地)不同,把不同的事情做好。对于您的场景,您可以这样做:

#!/bin/bash

eval set -- $(getopt -n $0 -o "-rvxl:" -- "$@")

declare r v x l
declare -a files
while [ $# -gt 0 ] ; do
        case "$1" in
                -r) r=1 ; shift ;;
                -v) v=1 ; shift ;;
                -x) x=1 ; shift ;;
                -l) shift ; l="$1" ; shift ;;
                --) shift ;;
                -*) echo "bad option '$1'" ; exit 1 ;;
                *) files=("${files[@]}" "$1") ; shift ;;
         esac
done

if [ ${#files} -eq 0 ] ; then
        echo output file required
        exit 1
fi

[ ! -z "$r" ] && echo "r on"
[ ! -z "$v" ] && echo "v on"
[ ! -z "$x" ] && echo "x on"

[ ! -z "$l" ] && echo "l == $l"

echo "output file(s): ${files[@]}"

编辑:为完整起见,我提供了一个处理需要参数的选项的示例。

如果您使用的是getops,只需在您的案例陈述后按
$OPTIND-1
移位即可。然后,
$*
中剩下的将是其他所有内容,这可能是您想要的

shift $(( ${OPTIND} - 1 )); echo "${*}"

你正遭受着幻觉的折磨;使用
getopts
不需要带有标志字母前缀的强制参数。我试图从我的剧本语料库中找到一个合适的例子;这是一个半合理的近似值。它被称为
rcsunco
,用于取消RCS的签出。我知道,我已经有一段时间没有修改它了;我经常使用它(因为我还没有完全从RCS迁移)

这只是一个半合理的近似值;如果在可选参数后不提供任何文件名,脚本将不会悄悄地执行任何操作。但是,如果需要,可以检查强制参数在“shift”之后是否存在。我的另一个脚本确实有强制参数。它包括:

...
shift $(($OPTIND - 1))

case $# in
2)  case $1 in
    install)    MODE=Installation;;
    uninstall)  MODE=Uninstallation;;
    *)          usage;;
    esac;;
*)  usage;;
esac
因此,该命令(
jlss
)可以接受可选参数,例如
-d$HOME
,但需要
install
uninstall
后跟要安装的东西的名称。基本的使用方式是:

jlss install program
但可选模式是:

jlss -d $HOME -u me -g mine -x -p install program
我没有显示所有的
jlss
,因为它有大约12个选项-它没有
rcsunco
那么紧凑


如果您在处理选项参数之前先处理强制参数,那么您需要做更多的工作:

  • 你会拿起强制性的论点,把它们移开
  • 然后处理带有标志的可选参数
  • 最后,如果合适,处理额外的“文件名”参数
如果您正在处理包含选项参数的强制参数(在强制参数之前和之后),那么您还有更多的工作要做。这被许多VCS系统使用;CVS和GIT均拥有以下设施:

git -global option command [-sub option] [...]
在这里,运行一个
getopts
循环来获取全局选项;拿起强制性的论据;然后运行第二个
getopts
循环以获取子选项(可能还会在“file name”参数上运行最后一个循环)

生活难道不是很有趣吗?

这里有另一种“选择shell脚本”(不使用getopt或getopts)的方法:


我听到了一个完全相反的说法,那就是你不应该使用
getopt
,而应该使用
getopts
内置的

永远不要使用getopt(1)。getopt无法处理空参数字符串,或 带有嵌入空格的参数。请永远忘记它 存在

POSIX外壳(和其他)提供了安全使用的getopts 相反


这看起来正是我想要的。然而,有一个问题是:如果我想允许一个带有参数的标志(例如,-l file.txt),那么语法是什么?再次感谢。请参阅getopt手册页。简单地说:在选项后面加一个冒号(例如,
“-rv:x”
,这需要v取一个参数)。还支持长选项,这是它胜过getopts内置的一种方式。请注意,您必须自己处理附加的非选项参数。@提问者:请注意,某些版本的
getopt
存在问题。从
man
页面:“getopt(1)的传统实现无法处理参数和非选项参数中的空格和其他(特定于shell的)特殊字符。”有关更多详细信息以及测试您的版本是否存在这些问题的方法,请参阅。只需检查$#以确保传递了正确数量的必需参数,然后像往常一样以$1、$2等形式访问它们。
git -global option command [-sub option] [...]