Bash Shell脚本-检查标志并获取其值


78

我正在尝试制作一个shell脚本,旨在像这样运行:

script.sh -t application

首先,在我的脚本中,我想检查脚本是否已使用-t标志运行。例如,如果运行时没有这样的标志,我希望它出错:

script.sh

其次,假设存在-t标志,我想获取该值并将其存储在我可以在脚本中使用的变量中,例如:

FLAG="application"

到目前为止,我在这方面取得的唯一进步是$ @可以获取所有命令行参数,但是我不知道这与标志之间的关系,或者甚至是不可能的。


Answers:


124

您应该阅读此getopts教程。

-a需要参数的switch的示例:

#!/bin/bash

while getopts ":a:" opt; do
  case $opt in
    a)
      echo "-a was triggered, Parameter: $OPTARG" >&2
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1
      ;;
    :)
      echo "Option -$OPTARG requires an argument." >&2
      exit 1
      ;;
  esac
done

就像greybot所说的(getopt!= getopts):

外部命令getopt(1)永远不会安全使用,除非您知道 它是GNU getopt,并以GNU特定的方式调用它,确保GETOPT_COMPATIBLE不在环境中。请改用getopts(内置的shell),或简单地在位置参数上循环。


1
getoptsbash内置的,但也有一个外部getopt程序可以与任何POSIX兼容的外壳一起使用。
chepner

3
外部命令getopt(1)永远不会安全使用,除非您知道它是GNU getopt,并以GNU特定的方式调用它,确保GETOPT_COMPATIBLE不在环境中。请改用getopts(内置的shell),或简单地在位置参数上循环。
吉尔·奎诺

对不起,我需要这个给我哑巴。如果它是内置的bash,则可以在debian中运行shell
Jimmy

getopts教程很简单,并提供了有用的示例。如果您遇到这篇文章,绝对值得一读。
史蒂文·豪威尔

同意先前的评论:getopts教程非常值得花时间阅读,包括评论,其中一些评论提供了高级/替代用法。
弗朗索瓦·鲍耶

29

$#抢的参数的数目,如果它不等于2有没有提供了足够的论据:

if [ $# -ne 2 ]; then
   usage;
fi

接下来,检查是否$1等于-t,否则使用未知标志:

if [ "$1" != "-t" ]; then
  usage;
fi

最后存放$2FLAG

FLAG=$2

注意:usage()是一些显示语法的函数。例如:

function usage {
   cat << EOF
Usage: script.sh -t <application>

Performs some activity
EOF
   exit 1
}

这可能有效,但是当我要使用多个标志时会发生什么?
killjoy18年


11

这是一个通用的简单命令参数界面,您可以将其粘贴到所有脚本的顶部。

#!/bin/bash

declare -A flags
declare -A booleans
args=()

while [ "$1" ];
do
    arg=$1
    if [ "${1:0:1}" == "-" ]
    then
      shift
      rev=$(echo "$arg" | rev)
      if [ -z "$1" ] || [ "${1:0:1}" == "-" ] || [ "${rev:0:1}" == ":" ]
      then
        bool=$(echo ${arg:1} | sed s/://g)
        booleans[$bool]=true
        echo \"$bool\" is boolean
      else
        value=$1
        flags[${arg:1}]=$value
        shift
        echo \"$arg\" is flag with value \"$value\"
      fi
    else
      args+=("$arg")
      shift
      echo \"$arg\" is an arg
    fi
done


echo -e "\n"
echo booleans: ${booleans[@]}
echo flags: ${flags[@]}
echo args: ${args[@]}

echo -e "\nBoolean types:\n\tPrecedes Flag(pf): ${booleans[pf]}\n\tFinal Arg(f): ${booleans[f]}\n\tColon Terminated(Ct): ${booleans[Ct]}\n\tNot Mentioned(nm): ${boolean[nm]}"
echo -e "\nFlag: myFlag => ${flags["myFlag"]}"
echo -e "\nArgs: one: ${args[0]}, two: ${args[1]}, three: ${args[2]}"

通过运行命令:

bashScript.sh firstArg -pf -myFlag "my flag value" secondArg -Ct: thirdArg -f

输出将是这样的:

"firstArg" is an arg
"pf" is boolean
"-myFlag" is flag with value "my flag value"
"secondArg" is an arg
"Ct" is boolean
"thirdArg" is an arg
"f" is boolean


booleans: true true true
flags: my flag value
args: firstArg secondArg thirdArg

Boolean types:
    Precedes Flag(pf): true
    Final Arg(f): true
    Colon Terminated(Ct): true
    Not Mentioned(nm): 

Flag: myFlag => my flag value

Args: one => firstArg, two => secondArg, three => thirdArg

基本上,参数分为标志布尔值和通用参数。通过这种方式,用户只要将通用参数(如果有)保持指定顺序,就可以将标志和布尔值放在任何地方。

现在,让我,您再也不必处理bash参数解析了!

您可以在此处查看更新的脚本

在过去的一年中,这非常有用。现在,它可以通过在变量之前加上范围参数来模拟范围。

像这样调用脚本

replace() (
  source $FUTIL_REL_DIR/commandParser.sh -scope ${FUNCNAME[0]} "$@"
  echo ${replaceFlags[f]}
  echo ${replaceBooleans[b]}
)

看起来不像我实现了参数范围,不知道为什么我猜我还不需要它。


2
这是一个很好的答案:我将其放置在脚本中再走了一步,然后将其别名为.bashrc文件中的arg_handler。然后在每个脚本的顶部粘贴:source arg_handler; arg_handler "$@"
J.Warren,

但是-pf应该不是两个单独的标志,因为它不会以两个破折号开头吗?如在p和f中。
詹姆斯·崔基

1

尝试shFlags-Unix shell脚本的高级命令行标志库。

http://code.google.com/p/shflags/

它非常好,非常灵活。

标志类型:这是您可以执行的DEFINE_ *的列表。所有标志均具有名称,默认值,帮助字符串和可选的“短”名称(一个字母的名称)。一些标志具有其他自变量,这些自变量用该标志描述。

DEFINE_string:接受任何输入,并将其解释为字符串。

DEFINE_boolean:通常不接受任何参数:说--myflag将FLAGS_myflag设置为true,或者说--nomyflag将FLAGS_myflag设置为false。或者,您可以说--myflag = true或--myflag = t或--myflag = 0或--myflag = false或--myflag = f或--myflag = 1传递选项与传递选项一次。

DEFINE_float:接受输入并将其解释为浮点数。由于shell本身不支持浮点数,因此仅将输入验证为有效的浮点值。

DEFINE_integer:接受输入并将其解释为整数。

特殊标志:有一些标志具有特殊含义:--help(或-?)以人类可读的方式打印所有标志的列表–flagfile = foo从foo读取标志。(尚未实现)-与getopt()中一样,终止标志处理

用法示例:

-- begin hello.sh --
 ! /bin/sh
. ./shflags
DEFINE_string name 'world' "somebody's name" n
FLAGS "$@" || exit $?
eval set -- "${FLAGS_ARGV}"
echo "Hello, ${FLAGS_name}."
-- end hello.sh --

$ ./hello.sh -n Kate
Hello, Kate.

注意:我从shflags文档中获取了此文本

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.