在bash中只确保2个命令行参数?

时间:2016-03-19 03:26:04

标签: bash

代码:cmd.sh

#!/bin/bash

if [ $# -ne 4 ]; then
    echo not 4
    exit 1
fi

while [[ $# > 1 ]]
do
key="$1"

case $key in
    -f|--file)
    FILE="$2"
    shift
    ;;
    -t|--type)
    TYPE="$2"
    shift
    ;;
    --default)
    DEFAULT=YES
    ;;
    *)
        # unknown option
    ;;
esac
shift
done
echo FILE = "${FILE}"
echo TYPE = "${TYPE}"

目标

如何确保用户始终必须输入filetype个参数,并确保他们始终输入2 arguments,而不是更多而不是更少。

修改

由于标志,更新了上面的代码,ne 4。

仅有效结果

$ ./cmd.sh -f asd -t def
FILE = asd
TYPE = def

当前问题

1

$ ./cmd.sh -f asd asd asd
FILE = asd
TYPE =

我没有包含-t标志但它仍然认为它是有效的。

2

$ ./cmd.sh -f asd -g asd
FILE = asd
TYPE =

我包含了无效的标记,但仍认为它有效。

#!/bin/bash

if [ $# -ne 4 ]; then
    echo not 4
    exit 1
fi

while [[ $# > 1 ]]
do
key="$1"

case $key in
    -f|--file)
    FILE="$2"
    shift
    ;;
    -t|--type)
    TYPE="$2"
    shift
    ;;
    --default)
    DEFAULT=YES
    ;;
    *)
        echo invalid option $key
        exit 1
    ;;
esac
shift
done
echo FILE = "${FILE}"
echo TYPE = "${TYPE}"

最后一期

如何忽略长度要求并检查它们是否键入-h或--help?我希望在这种情况下打印出用法。

MY ATTEMPT

#!/bin/bash

# Ensure that environment variables are not used by accident
FILE=
TYPE=
arg0="$(basename "$0" .sh)"

usage() { echo "Usage: $arg0 -f file -t type" >&2; exit 1; }
error() { echo "$arg0: $*" >&2; usage; }
help() { echo "Help: some help file" >&1; exit 0; }
version() { echo "Version: 1.0" >&1; exit 0; }

while [ $# -gt 1 ]
do
    case "$1" in
    -h|--help)
        help
        ;;
    -v|--version)
        version
        ;;
    -f|--file|-t|--type)
        ;;
    -*) error "unrecognized option $1";;
    *)  error "unexpected non-option argument $1";;
    esac
    shift
done

[ $# -eq 4 ] || usage

while [ $# -gt 1 ]
do
    case "$1" in
    -f|--file)
        [ -z "$FILE" ] || error "already specified file name $FILE"
        [ -z "$2" ] && error "empty file name specified after $1"
        FILE="$2"
        shift
        ;;
    -t|--type)
        [ -z "$TYPE" ] || error "already specified file type $TYPE"
        [ -z "$2" ] && error "empty type name specified after $1"
        TYPE="$2"
        shift
        ;;
    -*) error "unrecognized option $1";;
    *)  error "unexpected non-option argument $1";;
    esac
    shift
done

# Should never execute either of these errors
[ -z "$FILE" ] && error "no file name specified"
[ -z "$TYPE" ] && error "no type name specified"

echo FILE = "${FILE}"
echo TYPE = "${TYPE}"

这破坏了代码并开始抛出以下错误:

$ bash a2.sh -f typename -t asda
a2: unexpected non-option argument typename
Usage: a2 -f file -t type

下面的解决方案比我试图做的更优雅!

更新 - 测试

$ bash d2.sh -t type -f filename -V
FILE = filename
TYPE = type

$ bash d2.sh -h
d2.sh: no file name specified (and no --default)
Usage: d2 [-d|--default][-h|--help][-V|--version][{-f|--file} file] [{-t|--type} type]

$ bash d2.sh -V
d2.sh: no file name specified (and no --default)
Usage: d2 [-d|--default][-h|--help][-V|--version][{-f|--file} file] [{-t|--type} type]

2 个答案:

答案 0 :(得分:2)

您已经在检查是否有任何参数,所以您是否尝试检查是否有多于或少于2?

if [ $# -ne 2 ]; then
    # TODO: print usage
    exit 1
fi

 # rest of code here 

答案 1 :(得分:1)

这符合您的要求吗?我认为它涵盖了大多数基础,但如果您选择将一个空格或制表符串指定为文件名或类型名称,则脚本不会反对。

脚本a2.sh

#!/bin/bash

# Ensure that environment variables are not used by accident
FILE=
TYPE=
arg0="$(basename "$0" .sh)"

usage() { echo "Usage: $arg0 -f file -t type" >&2; exit 1; }
error() { echo "$arg0: $*" >&2; usage; }

[ $# -eq 4 ] || usage

while [ $# -gt 1 ]
do
    case "$1" in
    -f|--file)
        [ -z "$FILE" ] || error "already specified file name $FILE"
        [ -z "$2" ] && error "empty file name specified after $1"
        FILE="$2"
        shift
        ;;
    -t|--type)
        [ -z "$TYPE" ] || error "already specified file type $TYPE"
        [ -z "$2" ] && error "empty type name specified after $1"
        TYPE="$2"
        shift
        ;;
    -*) error "unrecognized option $1";;
    *)  error "unexpected non-option argument $1";;
    esac
    shift
done

# Should never execute either of these errors
[ -z "$FILE" ] && error "no file name specified"
[ -z "$TYPE" ] && error "no type name specified"

echo FILE = "${FILE}"
echo TYPE = "${TYPE}"

请注意,如果脚本中未初始化FILETYPE,则运行:

FILE=henry TYPE=ford bash a2.sh -f file -t type

会生成错误,因为FILE已经有一个值(或TYPE已经有一个具有不同参数的值)。确保您不会意外地获取环境变量非常重要。还有一种情况是说你的脚本中的变量应该是小写的(或者是大小写的),留下大写的环境变量。但是,您仍然需要设置小写变量 - 您可以轻松地将小写环境变量设置为大写,尽管大写是常规变量。

另请注意$*功能中error的谨慎,慎重和正确使用。虽然使用$@不会造成麻烦,但这次所需的结果是单个字符串,$*给出了这一点。 (通常,使用"$@"是正确的,但这是"…$*…"更好的情况。)

示例运行

$ bash a2.sh
Usage: a2 -f file -t type
$ bash a2.sh a
Usage: a2 -f file -t type
$ bash a2.sh a b
Usage: a2 -f file -t type
$ bash a2.sh a b c
Usage: a2 -f file -t type
$ bash a2.sh a b c d
a2.sh: unexpected non-option argument a
Usage: a2 -f file -t type
$ bash a2.sh a b c d e
Usage: a2 -f file -t type
$ bash a2.sh -f file -f file
a2: already specified file name file
Usage: a2 -f file -t type
$ bash a2.sh -t type -t typename
a2: already specified file type type
Usage: a2 -f file -t type
$ bash a2.sh -t type t typename
a2: unexpected non-option argument t
Usage: a2 -f file -t type
$ bash a2.sh -t type -k typename
a2: unrecognized option -k
Usage: a2 -f file -t type
$ bash a2.sh -t type -f filename
FILE = filename
TYPE = type
$ bash a2.sh --file firstname -f filename
a2: already specified file name firstname
Usage: a2 -f file -t type
$ bash a2.sh --type typename -t type
a2: already specified file type typename
Usage: a2 -f file -t type
$ bash a2.sh -f '' -t ''
a2: empty file name specified after -f
Usage: a2 -f file -t type
$ bash a2.sh -t '' -f ''
a2: empty type name specified after -t
Usage: a2 -f file -t type
$

处理--help--version--default

另见评论链(工作中的懒惰)。修订版的代码可能是:

#!/bin/bash

# Ensure that environment variables are not used by accident
FILE=
TYPE=
arg0="$(basename "$0" .sh)"

usemsg="Usage: $arg0 [-d|--default][-h|--help][-V|--version][{-f|--file} file] [{-t|--type} type]"
usage() { echo "$usemsg" >&2; exit 1; }
error() { echo "$0: $*" >&2; usage; }

while [ $# -gt 0 ]
do
    case "$1" in
    -f|--file)
        [ -z "$FILE" ] || error "already specified file name $FILE"
        [ -z "$2" ] && error "empty file name specified after $1"
        FILE="$2"
        shift
        ;;
    -t|--type)
        [ -z "$TYPE" ] || error "already specified file type $TYPE"
        [ -z "$2" ] && error "empty type name specified after $1"
        TYPE="$2"
        shift
        ;;
    -h|--help)
        echo "$usemsg"
        echo ""
        echo "  [-f|--file] filename   Use the specified file name"
        echo "  [-t|--type] typename   Use the specified type name"
        echo "  [-h|--help]            Print this help message and exit"
        echo "  [-V|--version]         Print the version information and exit"
        echo "  [-d|--default]         Use the defaults (default-file and default-type)"
        exit 0
        ;;
    -V|--version)
        echo "$arg0 Version 1.02 (2016-03-18)"
        exit 0
        ;;
    -d|--default)
        [ -z "$FILE" ] && FILE="default-file"
        [ -z "$TYPE" ] && TYPE="default-type"
        ;;
    -*) error "unrecognized option $1";;
    *)  error "unexpected non-option argument $1";;
    esac
    shift
done

[ -z "$FILE" ] && error "no file name specified (and no --default)"
[ -z "$TYPE" ] && error "no type name specified (and no --default)"

echo FILE = "${FILE}"
echo TYPE = "${TYPE}"

在选项处理循环之后,我很少测试参数的数量。您还应该查看使用getoptsgetopt(1)的GNU扩展版本。