【问题标题】:Returning array from a Bash function从 Bash 函数返回数组
【发布时间】:2013-02-12 18:24:42
【问题描述】:

我正在制作一个 bash 脚本,但遇到了问题。所以假设我得到了这个

function create_some_array(){
  for i in 0 1 2 3 .. 10
  do
    a[i]=$i
  done
}

create_some_array
echo ${a[*]}

有什么方法可以让我完成这项工作吗?我已经搜索了很多,但没有发现任何工作。 我认为将a[] 设为全局变量应该可行,但我找不到在我的代码中实际可行的东西。有什么方法可以将数组从函数返回到主程序?

提前致谢

【问题讨论】:

  • 这段代码没有任何问题。不要发明代码来显示问题。向我们展示导致问题的实际代码。
  • 欢迎来到 Stack Overflow。请准确发布所有相关错误消息,以改进您的问题。此外,请确保包含格式正确的预期输出示例,以便人们了解您想要达到的结果。
  • @depesz:我半同意。我认为提问者应该“发明代码来显示问题”——但是(s)他必须确保它(如你所说)是“导致问题的实际代码”。这被称为SSCCE -- a short, self-contained, correct (compilable) example
  • @ruakh:好吧,他/她导致问题的代码。只是他发明的用于展示它的版本 - 不包含问题。不幸的是(至少在 IRC 上)人们对某事有问题但表现出不同的情况是很常见的。
  • “不会工作”不是技术描述。尝试使用 bash -x script_name 运行您的脚本,这将跟踪正在发生的事情。

标签: arrays bash function shell return-value


【解决方案1】:

如前所述,这可以正常工作。它在您的实际代码中不起作用的最可能原因是您碰巧在子外壳中运行它:

cat textfile | create_some_array
echo ${a[*]}

不起作用,因为管道中的每个元素都在子shell中运行,并且

myvalue=$(create_some_array)
echo ${a[*]}

不起作用,因为命令扩展发生在子 shell 中。

【讨论】:

  • j=ls -i "$i" | awk '{print $1}';索引节点[计数]=$j;这是我插入数组的部分。当我尝试在函数之外回显它时它不起作用
【解决方案2】:

当数组中有空格时,这将无法按预期工作:

function create_some_array() {
    local -a a=()
    for i in $(seq $1 $2); do
        a[i]="$i $[$i*$i]"
    done
    echo ${a[@]}
}

更糟糕的是:如果你尝试从外部“a”获取数组索引,结果是一个标量:

echo ${!a[@]}

即使赋值为数组也无济于事,因为可能的引用自然会被回显线删除,并且无法操纵评估顺序来逃避引用:尝试

function create_some_array() {
...
    echo "${a[@]}"
}

a=($(create_some_array 0 10))
echo ${!a[@]}

不过,printf 似乎也无济于事:

function create_some_array() {
...
    printf " \"%s\"" "${a[@]}"
}

一方面似乎产生了正确的输出:

$ create_some_array 0 3; echo
 "0 0" "1 1" "2 4" "3 9"

但分配对另一个不起作用:

$ b=($(create_some_array 0 3))
$ echo ${!b[@]}
0 1 2 3 4 5 6 7

所以我的最后一个技巧是按如下方式进行分配:

$ eval b=("$(create_some_array 0 3)")
$ echo -e "${!b[@]}\n${b[3]}"
0 1 2 3
3 9

塔塔啊!

P.S.: printf "%q " "${a[@]}" 也可以正常工作...

【讨论】:

  • 烦人!这可行,但我的 IDE 给了我一个错误,它不会抑制......解析在这里停止。无效使用parantheses? ..烦人但+1
【解决方案3】:

您可以将数组设为函数本地,然后将其返回:

function create_some_array(){
    local -a a=()
    for i in $(seq $1 $2); do
        a[i]=$i
    done
    echo ${a[@]}
}

declare -a a=()

a=$(create_some_array 0 10)

for i in ${a[@]}; do
   echo "i = " $i
done

【讨论】:

    【解决方案4】:

    您好,这是我的解决方案:

    show(){
        local array=()
        array+=("hi")
        array+=("everything")
        array+=("well?")
        echo "${array[@]}"
    }
    
    for e in $(show);do
        echo $e
    done
    

    试试这个代码:https://www.tutorialspoint.com/execute_bash_online.php

    【讨论】:

    • 这工作 +1 但它有点烦人因为如果你转储数组的长度它总是 1 - 我的 IDE 警告我它已转换为字符串并且控制台输出同意
    【解决方案5】:

    shbash 对我来说都适用:

    arr1=("192.168.3.4" "192.168.3.4" "192.168.3.3")
    
    strArr=$(removeDupes arr1) # strArr is a string
    for item in $strArr; do arr2+=("$item"); done # convert it to an array
    len2=${#arr2[@]} # get array length
    echo "${len2}" # echo length
    
    eval arr3=("$(removeDupes arr1)") # shellcheck does not like this line and won't suppress it but it works
    len3=${#arr3[@]} # get array length
    echo "${len3}" # echo length
    

    顺便说一句,removeDupes 函数如下所示:

    removeDupes() {
      arg="$1[@]"
      arr=("${!arg}")
      len=${#arr[@]}
      resultArr=()
      # some array manipulation here
      echo "${resultArr[@]}"
    }
    

    此答案基于 @Hans 和 @didierc 的答案,但更好地解释和简化了答案

    【讨论】:

      猜你喜欢
      • 2019-10-20
      • 1970-01-01
      • 2011-07-22
      • 2012-08-17
      • 1970-01-01
      • 2021-11-24
      • 2013-05-15
      • 2017-01-26
      • 2014-11-20
      相关资源
      最近更新 更多