【问题标题】:Define a local array in a bash function and access it outside that function在 bash 函数中定义一个本地数组并在该函数之外访问它
【发布时间】:2015-05-16 19:37:21
【问题描述】:

我正在尝试在 bash 函数中定义一个本地数组并在该函数之外访问它。

我意识到 BASH 函数不返回值,但我可以将计算结果分配给全局值。我希望这段代码能够将 array[] 的内容回显到屏幕上。我不确定它为什么会失败。

function returnarray
{
local array=(foo doo coo)
#echo "inside ${array[@]}"
}


targetvalue=$(returnarray)
echo ${targetvalue[@]}

【问题讨论】:

  • 它说什么?你检查了this 主题。也许你在函数名之后缺少 ()。

标签: arrays bash function


【解决方案1】:

你有两个选择。第一个是@choroba 规定的,它可能是最好和最简单的:不要在本地定义你的数组。

returnarray() {
    array=(foo doo coo) # NOT local
}

# call your function
returnarray
# now the array is in array and you may copy it for later use as follows:
targetvalue=( "${array[@]}" )
# print it to check:
declare -p targetvalue

这是整洁、简单、安全的,完全避免使用子shell(因此更高效)。但是,它有一个警告:它不适用于稀疏数组(但这应该是一个小细节)。还有一个小缺点:需要复制数组。


另一种选择是将变量名称传递给您的函数,并让函数直接生成数组。这使用了 namerefs,并且仅在 Bash 4.3 之后才可用(但它真的很好——如果可以的话就使用它!):

generatearray() {
    # $1 is array name in which array is generated
    local -n array="$1" || return 1
    array=( foo doo coo )
}
# call function that constructs the array with the array name
generatearray targetvalue
# display it
declare -p targetvalue

【讨论】:

    【解决方案2】:

    要使变量可以从外部访问,请不要将其声明为local。使其全球化。

    【讨论】:

      【解决方案3】:

      首先,正如您所说,bash 函数没有返回值。所以传递本地值的唯一方法是echo它。

      但是,如果将其解释为数组,这将导致您的目标值在索引 0 中回显所有内容。要告诉 bash 将这些部分视为数组部分,您必须用括号将它们括起来 - 来自 bash 手册:

      数组被分配给使用形式的复合赋值 name=(value1 ... valuen),其中每个值的形式为 [sub- 脚本]=字符串。

      #!/bin/bash
      
      function returnarray
      {
          local array=(foo doo coo)
          echo "${array[@]}"
      }
      
      
      targetvalue=($(returnarray))
      echo ${targetvalue[@]}
      echo ${targetvalue[1]}
      

      但是,所有这些实际上都是围绕bash 的工作原理进行的编程。全局定义数组会更好。

      由于使用echo 使得 bash 解释值,这仅适用于如果数组的值不受 bash 影响,例如值可能不包含通配符或空格,通配符将被扩展为匹配文件一个值中的空格会转换成多个数组值。

      【讨论】:

      • 这也受路径名扩展的影响。
      • @gniourf_gniourf:这种方法可能有太多限制。我想知道是否应该将其全部删除。
      • 这取决于您……您认识到严重的缺点实际上是件好事。通常提倡这种方法的人会尝试修复这些缺陷:例如,他们会使用set -f 来禁用路径名扩展。然后,关于空间,他们会做一些疯狂的事情,比如设置IFS=$'\n' 而不是echo "${array[@]}" 会使用printf '%s\n' "${array[@]}"。然后,在被指出它仍然在字段中使用换行符后,他们要么投降(但这只会发生在聪明的人身上),要么声称这不太可能,或者将使用printf%q,后跟eval
      【解决方案4】:

      看看这个,带空格和其他字符可能没问题....

      #!/bin/bash
      function returnarray
      {
      newname=$1
      local array=(foo doo coo)
      declare -p array | sed "s/array/$newname/g"
      }
      
      eval $(returnarray glob)
      echo elm0 ${glob[0]}
      echo elm1 ${glob[1]}
      echo elm2 ${glob[2]}
      

      How to return an array in bash without using globals?

      编辑:关于“数组”的评论是正确的……这是一个固定版本。 sed 用法我不介意...

      #!/bin/bash
      function returnarray
      {
      newname=$1
      local array=(foo doo coo "declare -a array" aa)
      declare -p array | sed "s/^declare -a array/declare -a $newname/"
      }
      
      eval $(returnarray glob)
      echo elm0 ${glob[0]}
      echo elm1 ${glob[1]}
      echo elm2 ${glob[2]}
      echo elm2 ${glob[3]}
      echo elm2 ${glob[4]}
      

      【讨论】:

      • 很好,谢谢,但我想知道 eval 是否适用于数组将包含用户输入数据的用例。 mywiki.wooledge.org/BashFAQ/048
      • @Dave:正如所写(不带引号),这根本不安全。此外,使用sed 会破坏该解决方案:如果array 出现在数组的任何字段中,就会出现问题……这是一个丑陋的解决方案,因为它不是纯Bash :)
      【解决方案5】:

      您可以声明局部变量,然后 printf 一个逗号分隔值字符串,它可以很好地转换为数组。关键是使用 printf 而不是 echo。

      http://wiki.bash-hackers.org/commands/builtin/read

      使用 printf,因为(取决于设置),echo 可能会解释一些 baskslash-escapes 或开关(如 -n)。

      代码:

      #Return csv of project.id's
      function get_project() {
        local qry="select id from ${DB}.projects where identifier=\"${1}\";"
        local ids=`sudo -u ${DB_USER} ${DB_LOCATION} -u ${DB_USER} -p${DB_PASS} -s -e "${qry}"`
        #return
        while read -r element; do printf "%s," "$element"; done <<< "$ids"
      }
      #Return csv of member.id's
      function get_members() {
        local qry="select user_id from ${DB}.members where project_id=${1};"
        local ids=`sudo -u ${DB_USER} ${DB_LOCATION} -u ${DB_USER} -p${DB_PASS} -s -e "${qry}"`
        #return
        while read -r element; do printf "%s," "$element"; done <<< "$ids"
      }
      projects=( $(get_project "newuser1") )
      declare -p projects
      member_ids=( $(get_members $projects) )
      declare -p member_ids
      

      终端:

      root@dev:~# ./batch_memberships.sh
      declare -a projects='([0]="439")'
      declare -a member_ids='([0]="315" [1]="1")'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-11-04
        • 2012-10-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多