【问题标题】:bash parse options from string created in other methodbash 解析在其他方法中创建的字符串的选项
【发布时间】:2021-11-07 23:49:04
【问题描述】:

我有一个函数可以接受不同组合的参数。它们的设置方式取决于其他条件,因此我创建了一种设置方法。

#!/bin/bash

myFunc() {
    while getopts m:t::T::rp:: arg; do
        case "$arg" in
            m)  log_msg="$OPTARG";;
            t)  timeout="$OPTARG";;
            T)  timeout_msg="$OPTARG";;
            r)  retry="yes";;
            p)  postpone="$OPTARG";;
            *)  die "invalid arguments $*";;
        esac
    done

    #doStuff...
}

setupOpts() {
    local name="$1"
    local param="$2"
    local err_msg="$3"
    if someTest "$name"; then
        # case all
        echo "-t 9 -T "$err_msg" -p "$name" -r"
    elif someOtherTest "$name" "$param"; then
        echo "-t 120 -T "$err_msg" -p "$name""
    else
        echo "-t 300 -T "$err_msg""
    fi
}

mainFunc() {
   # some stuff...
   opts="$(setupOpts "$someName" "$someParam" "Some Err Msg")"
   myFunc -m "Some Msg" "$opts"
}

我无法让这个工作。例如。当case all(见代码中的注释)为真时:

opts="$(setupOpts "peter-pan" "$someParam" "Some Err Msg")"
# -> results in: myFunc -m "some Msg" -t 9 -T "Some Err Msg" -p "peter-pan" -r

但是,-t 和后面的参数没有被正确解析。我想这与引用和分词有关。

取决于报价:

myFunc -m "Some Msg" "$opts":

timeout=9 -T "Some Err Msg" -p "peter-pan" -r
timeout_msg=
postpone=
retry=

或

myFunc -m "Some Msg" $opts:

timeout=9
timeout_msg=Some
postpone=
retry=

正确的是

timeout=9
timeout_msg=Some Err Msg
postpone=peter-pan
retry=yes

我尝试了其他不同的方法,例如使用转义引号 (echo "-t 9 -T "\"Some Err Msg\"" -p "$argOne" -r") 或使用不带引号的 echo。

这是否可以使用 bash 以某种方式实现,还是我在这里达到了限制?

PS:在myFunc 中进行设置也可以,但这不是我回答的解决方案。我想知道这种方法是否适用于 bash。

【问题讨论】:

  • 请更新问题的详细信息以重现您的问题,对于初学者:someTest 和 someOtherTest 的定义
  • 两者都是检查某些条件并根据该条件返回 0/1 的函数,例如如果可以重新部署虚拟机。我看不出它们的确切定义如何解决这个问题。 setupOpts() 的输出应根据条件为真或默认为 else 部分而改变。您可以为此使用任何测试,例如如果名称是某个字符串。
  • 是的,我明白这些功能应该做什么;我指出,当示例代码无法运行(在我们的环境中)时,人们更难重现该问题,更不用说提出建议的解决方案了;无论如何,假设setupOpts() 按预期运行,唯一的问题是调用myFunc() 时的引用/分词......我的回答解决了这个问题;或者...
  • 在bash command line args as array 上的谷歌搜索带来了许多关于此主题的点击,例如this 和this
  • 感谢您的支持。下次我会考虑您的观点并发布复制/粘贴示例。关于谷歌搜索:我进行了广泛的搜索,但没有找到任何可行的方法,但我发现一些提示,由于 bash 限制,它甚至可能无法正常工作。我没有搜索bash command line args as array,因为我没有这个想法,因此发布了这个问题以询问它是否可能(参见 PS)。正如您从接受的答案中看到的那样,简单地将 args 转换为数组是行不通的,我需要将它与 nameref 结合起来。

标签: bash


【解决方案1】:

由于引用的复杂性,您可以将 nameref 与数组结合使用:

#!/usr/bin/env bash

myFunc() {
    while getopts m:t::T::rp:: arg; do
        case "$arg" in
            m)  log_msg="$OPTARG";;
            t)  timeout="$OPTARG";;
            T)  timeout_msg="$OPTARG";;
            r)  retry="yes";;
            p)  postpone="$OPTARG";;
            *)  die "invalid arguments $*";;
        esac
    done

    #doStuff...
}

setupOpts() {
    local name="$1"
    local param="$2"
    local err_msg="$3"
    declare -n inner_opts=$4
    if someTest "$name"; then
        # case all
        inner_opts=(-t 9 -T "$err_msg" -p "$name" -r)
    elif someOtherTest "$name" "$param"; then
        inner_opts=(-t 120 -T "$err_msg" -p "$name")
    else
        inner_opts=(-t 300 -T "$err_msg")
    fi
}

mainFunc() {
   # some stuff...
   local outer_opts
   setupOpts "someName" "someParam" "Some Err Msg" outer_opts
   myFunc -m "Some Msg" "${outer_opts[@]}"
}

mainFunc

【讨论】:

    【解决方案2】:

    如果没有 someTest 和 someOtherTest 的定义,我将无法重现 OP 的输出,所以 fwiw ...

    看起来(在我看来)setupOpts() 函数生成了一组要传递给 myFunc() 函数的命令行选项。假设setupOpts() 生成正确的输出,我猜一种解决方案是将setupOpts 的输出存储在一个数组中,例如:

    opts=( $(setupOpts "peter-pan" "$someParam" "Some Err Msg") )
    

    对myFunc() 的主要调用则变为:

    myFunc -m "Some Msg" "${opts[@]}"
    

    【讨论】:

      猜你喜欢
      • 2014-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-27
      • 1970-01-01
      • 1970-01-01
      • 2013-07-16
      • 1970-01-01
      相关资源
      最近更新 更多