【问题标题】:bash function with third arg is an array具有第三个参数的 bash 函数是一个数组
【发布时间】:2019-10-08 08:02:01
【问题描述】:

我正在尝试编写一个执行以下操作的 bash 函数:

  • 如果没有第三个参数,请运行命令。
  • 如果有第三个参数,则从第三个参数中取出每个参数并运行命令。

我遇到的问题是else 语句中命令--capabilities CAPABILITY_IAM 的最后一位,如果我有多个参数,我不想一直传入。

An error occurred (InsufficientCapabilitiesException) when calling the CreateStack operation: Requires capabilities : [CAPABILITY_NAMED_IAM]
// that means I need to pass in --capabilities CAPABILITY_IAM

有没有办法告诉 bash:嘿,从第 3 个参数中取出所有参数,然后在后面添加 --capabilities CAPABILITY_IAM?就像在 JavaScript 中一样,我可以这样做:

function allTogetherNow(a, b, ...c) {
  console.log(`${a}, ${b}, ${c}. Can I have a little more?`);
}

allTogetherNow('one', 'two', 'three', 'four')

这是我的功能:

cloudformation_create() {
    if [ -z "$3" ]; then
        aws cloudformation create-stack --stack-name "$1" --template-body file://"$2" --capabilities CAPABILITY_IAM
    else
        aws cloudformation create-stack --stack-name "$1" --template-body file://"$2" --parameters "${@:3}" --capabilities CAPABILITY_IAM
    fi
}

如果我不使用 bash 函数,第三个等参数看起来像这样:

aws cloudformation create-stack --stack-name MY_STACK_NAME --template-body file://MY_FILE_NAME --parameters ParameterKey=KeyPairName,ParameterValue=TestKey ParameterKey=SubnetIDs,ParameterValue=SubnetID1 --capabilities CAPABILITY_IAM

2019 年 5 月 22 日更新:

以下丹尼斯威廉姆森的回答。我试过了:

  • 以AWS方式传递参数:
cloudformation_create STACK_NAME FILE_NAME ParameterKey=KeyPairName,ParameterValue=TestKey ParameterKey=SubnetIDs,ParameterValue=SubnetID1

出现错误:

An error occurred (ValidationError) when calling the CreateStack operation: Parameters: [...] must have values
  • 作为字符串传入:
cloudformation_create STACK_NAME FILE_NAME "ParameterKey=KeyPairName,ParameterValue=TestKey ParameterKey=SubnetIDs,ParameterValue=SubnetID1"

出现错误:

An error occurred (ValidationError) when calling the CreateStack operation: ParameterValue for ... is required
  • 不带ParameterKeyParameterValue
cloudformation_create STACK_NAME FILE_NAME KeyPairName=TestKey SubnetIDs=SubnetID1

出现错误:

Parameter validation failed:
Unknown parameter in Parameters[0]: "PARAM_NAME", must be one of: ParameterKey, ParameterValue, UsePreviousValue, ResolvedValue
// list of all the params with the above error
  • 不带ParameterKeyParameterValue 并作为字符串传入。出现错误:
arameter validation failed:
Unknown parameter in Parameters[0]: "PARAM_NAME", must be one of: ParameterKey, ParameterValue, UsePreviousValue, ResolvedValue

我尝试了 Alex Harvey 的回答,得到了这个:

An error occurred (ValidationError) when calling the CreateStack operation: Template format error: unsupported structure.

【问题讨论】:

  • 我觉得这个功能不错。怎么不工作了?
  • @DennisWilliamson 最后需要--capabilities CAPABILITY_IAM。出于某种原因,我的 bash 函数接受了所有参数,但没有在最后添加功能。
  • 当您使用使用“${@:3}”(而不是星号)的 Bash 函数(就在上面的“这是我的函数:”下方)时会发生什么?
  • 我们不会在 Stack Overflow 上的问题标题中添加“已解决”。请发布您的解决方案作为答案。您甚至可以将自己的答案标记为已接受。
  • @Viet,仅供参考,“不受支持的结构”是因为我的拼写错误;我错过了“file://”位。我已经更新了。

标签: bash amazon-web-services amazon-cloudformation


【解决方案1】:

根据 LeBlue 的回答和对docs 的快速阅读,您似乎需要从函数的参数构建--parameters 的参数:

cloudformation_create () {
local IFS=,
local parameters="${*:3}"

#if block not shown
aws cloud_formation ... --parameters "$parameters" ...

这假定你的函数是这样调用的:

cloudformation_create foo bar baz=123 qux=456

也就是说,键值对已经形成。

上面的 sn-p 通过将 IFS 设置为逗号来工作。在引号内使用$* 会导致其中包含的元素使用IFS 的第一个字符连接。如果您需要在函数的另一部分使用分词功能,您可能需要在更改之前保存IFS 的当前值,然后在加入分配后恢复它。

因此,$parameters 的扩展将是baz=123,qux=456

【讨论】:

  • 对不起。这行不通。我会用我从你的代码中得到的更新我的问题。
【解决方案2】:

我不确定这是否能回答您的问题,但也许会对您有所帮助。

$#是参数个数。

$@ 将包含所有参数,您可以传递它。

#!/bin/bash

foo()
{
    echo "params in foo: " $#
    echo "p1: " $1
    echo "p2: " $2
    echo "p3: " $3
}

echo "number of paramters: " $#

foo $@ 3   # pass params and add one to the end

致电:

./test.sh 1 2

输出:

number of paramters:  2
params in foo:  3
p1:  1
p2:  2
p3:  3

【讨论】:

  • 谢谢@Chris。不幸的是,这不是我想要的,我需要这样的东西:foo $1 $2 $3 $4 (and so on) then does: do $1 and $2 and do $3 $4 $5 then do the last bit
【解决方案3】:

我怀疑参数扩展是错误的,因为--parameters 可能需要有 一个 参数。 要么引用 cloudformation_create 的所有参数,这些参数最终需要作为 --parameters 标志的值:

cloudformation_create "the-stack" "the-filename" "all the parameters"

或重写函数以"$*"扩展成多个参数(将每个参数合并为一个)

cloudformation_create () {
    ...
    else
        aws cloudformation ... --parameters "${*:3}" --capabilities CAPABILITY_IAM
    fi
}

这会将所有值保留为一个字符串/参数,两者都将转换为:

aws cloudformation  ... --parameters "all other parameters" --capabilities CAPABILITY_IAM

与您的版本相反:

aws cloudformation ... --parameters "all" "other" "parameters" --capabilities CAPABILITY_IAM

【讨论】:

  • 我想你可能很接近。 docs 表示--parameters 的参数是key=value 对的逗号分隔列表。
  • 我想你很接近了。就像@DennisWilliamson 上面写的一样,--parameters 是一个列表。我已经更新了我上面的问题。
【解决方案4】:

首先,感谢大家的帮助。

我已经意识到了这个问题(以及我的错误):

AWS 使用 Requires capabilities : [CAPABILITY_NAMED_IAM] 返回错误,而我的函数使用 [CAPABILITY_IAM]。 取决于带有与创建 IAM 相关的参数的模板,[CAPABILITY_NAMED_IAM][CAPABILITY_IAM] 是必需的。我发现答案here 很有帮助。

所以在我的例子中,bash 功能很好,对于我试图创建的模板,我需要传入--capabilities CAPABILITY_NAMED_IAM。我试过了,效果很好。

【讨论】:

    【解决方案5】:

    我会这样写:

    cloudformation_create() {
      local stack_name=$1
      local template_body=$2
      shift 2 ; local parameters="$@"
    
      local command=(aws cloudformation create-stack 
        --stack-name "$stack_name"
        --template-body "file://$template_body")
    
      [ ! -z "$parameters" ] && \
        command+=(--parameters "$parameters")
    
      command+=(--capabilities CAPABILITY_IAM)
    
      ${command[@]}
    }
    

    注意:

    • 调用shift 2 会导致$3 被旋转到$1,这样您就可以正常使用$@

    【讨论】:

    • 你可以做shift 2。将命令、选项和参数放入变量中是discouraged
    猜你喜欢
    • 2019-08-16
    • 2019-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-13
    • 2020-09-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多