AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / computer / 问题 / 1444568
Accepted
fma abd
fma abd
Asked: 2019-06-04 14:52:02 +0800 CST2019-06-04 14:52:02 +0800 CST 2019-06-04 14:52:02 +0800 CST

变量名存储在 bash 数组中;如何遍历数组并根据常见模式测试它们的值?

  • 772

团队,

我正在尝试实现一种功能,该功能由用户检查 ENV 中预定义变量列表中所有变量的内容,然后使用所有结果变量作为参数运行我的函数。

所以,有3种可能性:

1 - All variables hold same value 
[DatasetSize & BlockSize == DEFAULT ]

2 - All variables hold unique value 
[DatasetSize & BlockSize != DEFAULT ]

3 - Some are unique and some distinct. 
[DatasetSize || BlockSize = DEFAULT ]

我的代码在下面适用于案例 1 和案例 2,但不适用于案例 3。对于第三种情况,当任何变量具有“DEFAULT”时,它只执行第二个 elif 而不是第三个。

#!/bin/bash
#exit on fail without running next command
set -eo pipefail

export TestType="read"
export IOEngine="psync"
export DatasetSize="DEFAULT"
export BlockSize="NON-DEFAULT"

preset="DEFAULT"
declare -a static_vars=(TestType IOEngine)
declare -a dynamic_vars=(DatasetSize BlockSize )
declare -a vars=(TestType IOEngine DatasetSize BlockSize)

for var_name in "${vars[@]}"
do
  if [ -z "$(eval "echo \$$var_name")" ]; then
    echo "Missing environment variable $var_name"
    exit 1
  fi
done

overwrite_all() {
    printf "all defaults in func\n"
}
overwrite_some() {
    printf "some defaults in func\n"
}
overwrite_none() {
    printf " none defaults in func\n"
}
overwrite() {
    #not sure how to overwrite only those vars that have nonDEFAULT value.
    export DatasetSize="changed"
    export BlockSize="changed"
    echo "DatasetSize=$DatasetSize BlockSize=$BlockSize"
}
if [[ "$IOEngine" == "psync"  && ( "$TestType" == "read" || "$TestType" == "randread" ) ]]; then
    iter=1
    while [ $iter -lt 2 ]
    do
        echo "all are defaults; being to call your script with these parameters"
        echo $var_name
        if [[ ${dynamic_vars[@]} == $preset ]]; then
            echo "calling over_none"
            overwrite_none
        elif [[ ${dynamic_vars[@]} != "DEFAULT" ]]; then
            echo "calling over_all"
            overwrite_all
            overwrite
        elif [[ $DatasetSize == "DEFAULT" || $BlockSize == "DEFAULT" ]] && [[ $DatasetSize != "DEFAULT" && $BlockSize != "DEFAULT" ]]; then
                echo "calling over_some"
                overwrite_some
                overwrite
            else
            echo "done"
        fi
            iter=$[$iter+1]
        done
    else
        echo "ITengine not found"
    fi
    echo "out of loop"

输出:

calling over_all
all non-defaults in func
Data setSize=changed BlockSize=changed
out of loop

期望输出:

some defaults in func
DatasetSize=changed BlockSize=changed
bash array
  • 1 1 个回答
  • 667 Views

1 个回答

  • Voted
  1. Best Answer
    Kamil Maciorowski
    2019-06-08T00:59:11+08:002019-06-08T00:59:11+08:00

    我将解决我认为是您的代码中的主要缺陷。它像这样一行:

    if [[ ${dynamic_vars[@]} == $preset ]]; then
    

    你的片段[[ ${dynamic_vars[@]} == $preset ]]相当于

    [[ "DatasetSize BlockSize" == DEFAULT ]]
    

    这根本不符合您想要的逻辑。问题:

    1. (小问题或设计使然)。==运算符内部未加引号的右侧[[ … ]]被视为模式。DEFAULT不包含*也不包含,所以在这种情况下无关紧要;但通常你可能想要双引号$preset。

    2. Unquoted${array[@]}像 unquoted$string一样经历分词。如果你设置这个:

      array=(nospace "with space")
      string="nospace with space"
      

      then${array[@]}将扩展为三个实体,$string. 但是"${array[@]}"会扩展到两个实体,而"$string"会扩展到一个实体。您可以使用以下代码自行测试:

      sh -c 'echo $#' whatever ${array[@]}
      sh -c 'echo $#' whatever $string
      sh -c 'echo $#' whatever "${array[@]}"
      sh -c 'echo $#' whatever "$string"
      

      这意味着您实际上总是想使用"${array[@]}",因为数组的全部意义在于传递精确数量的参数(此处:2),其中一些可能包含空格等。

      您的特定数组包含变量名称。一般来说,这样的名称不能包含空格或其他字符,这使它们安全(我认为即使涉及文件名扩展)。您可以将它们放在一个(空格分隔)string或一个中并通过,或(但不是)array检索。这仍然是一个例外,它只起作用,因为变量的名称受到约束。${array[@]}"${array[@]}"$string"$string"

      所以你${dynamic_vars[@]}通常会扩展到两个实体("${dynamic_vars[@]}"通常会)。不过有一个问题:无论如何,内部未加引号的变量[[ … ]]都被视为单个实体(这对 来说是特殊的[[ … ]]),因此"DatasetSize BlockSize".

      请注意,如果您这样做了[[ "${dynamic_vars[@]}" == "$preset" ]],这将“有效”

      [[ "DatasetSize" "BlockSize" == "DEFAULT" ]]
      

      这在语法上是错误的( 的两边应该只有一个参数==)。

      但是[[ "DatasetSize BlockSize" == DEFAULT ]]nor [[ "DatasetSize" "BlockSize" == "DEFAULT" ]](甚至[[ "DatasetSize" == "DEFAULT" && "BlockSize" == "DEFAULT" ]],如果你以某种方式做到这一点)都不是你想要的。这将我们带到下一点。

    3. 您的dynamic_vars数组包含字符串,而不是变量或它们的值。我的意思是您可以轻松地从中获取DatasetSize(即文字DatasetSize字符串)。这显然不同于$DatasetSize扩展到的内容(即 string DEFAULT)。在将结果与 进行比较之前,您需要额外的扩展级别$preset。

      您实际上在其他地方执行额外的扩展。在这个片段中:

      for var_name in "${vars[@]}"
      do
        if [ -z "$(eval "echo \$$var_name")" ]; then
          echo "Missing environment variable $var_name"
          exit 1
        fi
      done
      

      eval "echo \$$var_name"扩展名称存储在另一个变量中的变量是一种麻烦的方法(术语是间接扩展)。在 Bash 中有这样的特殊语法:(${!var_name}通常你想用双引号引起来)。相关行可以是

      if [ -z "${!var_name}" ]; then
      

      注意"$(eval "echo \$$var_name")"是危险的。如果最终变量在其他人的控制之下,他们可以将代码注入到您的脚本中。"${!var_name}"在这件事上是安全的。

      同样在此代码段中,您使用了for var_name in "${vars[@]}". 这是遍历数组的好方法。您可以使用这种方法来测试"${dynamic_vars[@]}"代码后面的每个名称。


    把这些放在一起,你可以通过计算保持默认值的变量的数量来得到你想要的;像这样:

    #!/bin/bash
    
    DatasetSize="DEFAULT"
    BlockSize="NON-DEFAULT"
    
    preset="DEFAULT"
    declare -a dynamic_vars=( DatasetSize BlockSize )
    
    number_of_dynamic_vars="${#dynamic_vars[@]}"
    number_of_default_values=0
    
    for var in "${dynamic_vars[@]}"
    do
      [[ "${!var}" == "$preset" ]] && ((number_of_default_values++))
    done
    
    if [[ "$number_of_default_values" -eq 0 ]]; then
      echo "No defaults"
    elif [[ "$number_of_default_values" -eq "$number_of_dynamic_vars" ]]; then
      echo "All defaults"
    else
      echo "Mixed"
    fi
    

    可以重建(优化)通用算法,因此尽快公布“混合”(最佳情况:测试前两个变量后)。然而,对于少数变量来说,这是不值得的;对于两个(或更少)变量,你总是需要检查它们。

    请注意,我没有if按照您的原始订单测试 ( )。我在(可能性 1)0之前测试(你的可能性 2 $number_of_dynamic_vars)。这样,如果dynamic_vars数组恰好有 0 个元素,我将得到“无默认值”而不是“所有默认值”。这只是因为在这种极端情况下,我希望看到“无默认值”。但是如果“无默认值”意味着很多额外的工作而“所有默认值”没有,我想把这个边缘案例放在“所有默认值”篮子里(即$number_of_dynamic_vars首先测试)。


    补充说明:

    • [并且[[是不同的。在大多数情况下,我使用[[even if[就足够了。
    • 我在里面用双引号引用了变量[[ … ]],尽管在很多情况下不需要引用。我的前提是“总是引用你的变量,除非你知道你在做什么并且有充分的理由不这样做”。只有少数情况下您不能引用来获得您想要的东西;有些情况下引用并不重要;并且在很多情况下,缺乏适当的引用会让您感到痛苦。
    • 0

相关问题

  • 在 macOS High Sierra 的终端中设置环境变量时遇到问题

  • 对于 cp 或 mv,是否有等同于 cd - 的东西?

  • Notify-发送窗口下出现的通知

  • Excel 数组(2 个变量)

  • 如何从 WSL 打开 office 文件

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    Windows 照片查看器因为内存不足而无法运行?

    • 5 个回答
  • Marko Smith

    支持结束后如何激活 WindowsXP?

    • 6 个回答
  • Marko Smith

    远程桌面间歇性冻结

    • 7 个回答
  • Marko Smith

    Windows 10 服务称为 AarSvc_70f961。它是什么,我该如何禁用它?

    • 2 个回答
  • Marko Smith

    子网掩码 /32 是什么意思?

    • 6 个回答
  • Marko Smith

    鼠标指针在 Windows 中按下的箭头键上移动?

    • 1 个回答
  • Marko Smith

    VirtualBox 无法以 VERR_NEM_VM_CREATE_FAILED 启动

    • 8 个回答
  • Marko Smith

    应用程序不会出现在 MacBook 的摄像头和麦克风隐私设置中

    • 5 个回答
  • Marko Smith

    ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] 证书验证失败:无法获取本地颁发者证书 (_ssl.c:1056)

    • 4 个回答
  • Marko Smith

    我如何知道 Windows 安装在哪个驱动器上?

    • 6 个回答
  • Martin Hope
    Albin 支持结束后如何激活 WindowsXP? 2019-11-18 03:50:17 +0800 CST
  • Martin Hope
    fixer1234 “HTTPS Everywhere”仍然相关吗? 2019-10-27 18:06:25 +0800 CST
  • Martin Hope
    Kagaratsch Windows 10 删除大量小文件的速度非常慢。有什么办法可以加快速度吗? 2019-09-23 06:05:43 +0800 CST
  • Martin Hope
    andre_ss6 远程桌面间歇性冻结 2019-09-11 12:56:40 +0800 CST
  • Martin Hope
    Riley Carney 为什么在 URL 后面加一个点会删除登录信息? 2019-08-06 10:59:24 +0800 CST
  • Martin Hope
    zdimension 鼠标指针在 Windows 中按下的箭头键上移动? 2019-08-04 06:39:57 +0800 CST
  • Martin Hope
    Inter Sys Ctrl+C 和 Ctrl+V 是如何工作的? 2019-05-15 02:51:21 +0800 CST
  • Martin Hope
    jonsca 我所有的 Firefox 附加组件突然被禁用了,我该如何重新启用它们? 2019-05-04 17:58:52 +0800 CST
  • Martin Hope
    MCK 是否可以使用文本创建二维码? 2019-04-02 06:32:14 +0800 CST
  • Martin Hope
    SoniEx2 更改 git init 默认分支名称 2019-04-01 06:16:56 +0800 CST

热门标签

windows-10 linux windows microsoft-excel networking ubuntu worksheet-function bash command-line hard-drive

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve