【问题标题】:Parsing shell script arguments解析 shell 脚本参数
【发布时间】:2011-02-03 03:21:03
【问题描述】:
$myscript.sh -host blah -user blah -pass blah

我想将参数传递给它。

我习惯了$1$2$3....但是我想开始命名它们

【问题讨论】:

  • 考虑不配对选项,而是通过环境传递值:例如“host=hostname user=me myscript.sh”
  • stackoverflow.com/questions/192249/… 的副本,比较纯 bash switchgetopts(POSIX shell 内置)和 getopt(不推荐,除非它是 util-linux)版本,并且您使用其非 POSIX 功能来避免空参数等问题。)

标签: linux bash shell unix


【解决方案1】:

有很多方法可以解析 sh 中的参数。 Getopt 很好。这是一个手动解析事物的简单脚本:

#!/bin/sh
# WARNING: see discussion and caveats below
# this is extremely fragile and insecure

while echo $1 | grep -q ^-; do
    # Evaluating a user entered string!
    # Red flags!!!  Don't do this
    eval $( echo $1 | sed 's/^-//' )=$2
    shift
    shift
done

echo host = $host
echo user = $user
echo pass = $pass
echo args = $@

示例运行如下所示:

$ ./a.sh -host foo -user me -pass secret some args
host = foo
user = me
pass = secret
args = some args

请注意,这甚至不是远程强大的,也不是对安全性开放的 漏洞,因为脚本 eval 是用户构造的字符串。这仅仅是 旨在作为一种可能的做事方式的示例。更简单的方法是要求用户在环境中传递数据。在 bourne shell 中(即任何不属于 csh 系列的东西):

$ host=blah user=blah pass=blah myscript.sh

运行良好,变量$host$user$pass 将在脚本中可用。

#!/bin/sh
echo host = ${host:?host empty or unset}
echo user = ${user?user not set}
...

【讨论】:

  • 使用declare 代替eval 会更安全。
  • 除了@DennisWilliamson 的建议,我建议删除| tr -d '\012',因为这不是必需的——命令替换会自动修剪所有尾随的换行符。
  • @mklement0 我相信我实际上是在有意识地考虑内部换行符,考虑到试图处理这个问题是试图为一个极其脆弱的想法增加鲁棒性,这很奇怪。脆弱的方式有很多,这太有趣了。
  • 这是一个使用declare 而不使用sed(或eval)的示例:declare "${1#-}"=$2。请注意,此答案和此答案中的技术都不会处理两个或多个前导连字符或嵌入的连字符。此外,Bash 变量名称中不允许使用连字符。可以添加一个单独的步骤来将连字符转换为允许 的下划线:var=${1#-}; declare "${var//-/_}"="$2"
【解决方案2】:

这是处理多头和空头期权的简单方法:

while [[ $1 == -* ]]; do
    case "$1" in
      -h|--help|-\?) show_help; exit 0;;
      -v|--verbose) verbose=1; shift;;
      -f) if [[ $# > 1 && $2 != -* ]]; then
            output_file=$2; shift 2
          else 
            echo "-f requires an argument" 1>&2
            exit 1
          fi ;;
      --) shift; break;;
      -*) echo "invalid option: $1" 1>&2; show_help; exit 1;;
    esac
done

来自How can I handle command-line arguments (options) to my script easily?

【讨论】:

  • +1;但是请注意,这不会处理 compressed 选项,例如 -vf 代表 -v -f
  • d= (-_o ) 谢谢!在/bin/sh 上测试和工作(没有 Bash)。
【解决方案3】:

【讨论】:

  • 请注意,getopts 是内置的 Bash,而 getopt 是外部实用程序。前者仅适用于短选项(例如-e),而后者也适用于长选项(例如-foo)。请注意,有一些issues 必须解决后者(getopt 的更高版本问题更少)。
【解决方案4】:

我采用上面的 William Pursell 示例(在 Dennis Williamson 的建议下)用于以下格式的参数: 脚本 -param1=value1 -param2=value2 ...

这是带有单行参数解析器的代码(将其保存在文件“脚本”中):

#!/bin/bash

while echo $1 | grep ^- > /dev/null; do declare $( echo $1 | sed 's/-//g' | sed 's/=.*//g' | tr -d '\012')=$( echo $1 | sed 's/.*=//g' | tr -d '\012'); shift; done

echo host = $host
echo user = $user
echo pass = $pass

你这样称呼它:

script -host=aaa -user=bbb -pass=ccc

结果是

host = aaa
user = bbb
pass = ccc

有人知道解析参数的代码比上面的更短吗?

【讨论】:

    【解决方案5】:

    这是我的方法:

    host=""
    user=""
    pass=""
    while [[ "$#" -gt 0 ]]; do
        case $1 in
            -h|--host) host="$2"; shift ;;
            -u|--user) user="$2"; shift ;;
            -p|--pass) pass="$2"; shift ;;
            *) echo "Unknown parameter passed: $1" ;;
        esac
        shift
    done
    
    

    【讨论】:

      猜你喜欢
      • 2011-02-08
      • 1970-01-01
      • 1970-01-01
      • 2012-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多