如何使用 bash 创建多维数组或类似的数组?

如何使用 bash 创建多维数组或类似的数组?

我需要用 bash 创建一个多维数组,我读到 bash 中没有多维数组之类的东西。

这是我可能的数据,它们是什么样的以及我需要什么。这不是 bash 数组:

DATACOL = [
    "1"=>("Santiago","Barcelona","AWG","6792992","Male"),
    "2"=>("Santi","Texas","BGG","6792992","Male"),
    "3"=>("Tiago","Rio","GHA","6792992","Female") 
]

我怎样才能用一个简单的脚本做类似的事情?我对 bash 完全是个新手。

答案1

你不知道。如果您发现自己需要诸如多维数组之类的东西,则强烈表明您应该使用实际的编程语言而不是 shell。 Shell 并不是真正的编程语言,尽管它们可以(滥用)用作一种语言,但这应该只用于简单的事情。不幸的是,许多人似乎认为 shell 是适用于所有情况的正确工具,这会导致浪费大量精力尝试做 shell 无法完成或可能做得非常糟糕的事情,而不是使用专为特定情况设计的工具。工作。

也就是说,你可以使用以下方法将一些东西组合在一起名称引用:

可以使用声明或本地内置命令(请参阅 Bash 内置命令)的 -n 选项为变量分配 nameref 属性,以创建 nameref 或对另一个变量的引用。这允许间接操纵变量。每当 nameref 变量被引用、赋值、取消设置或修改其属性(除了使用或更改 nameref 属性本身)时,实际上都会对 nameref 变量的值指定的变量执行操作。 nameref 通常在 shell 函数中使用来引用其名称作为参数传递给函数的变量。例如,如果将变量名作为第一个参数传递给 shell 函数,则运行

declare -n ref=$1

函数内部创建一个 nameref 变量 ref,其值是作为第一个参数传递的变量名称。对 ref 的引用和赋值以及对其属性的更改均被视为对名称作为 $1 传递的变量的引用、赋值和属性修改。

例如,像这样:

#!/bin/bash

data1=("Santiago" "Barcelona" "AWG" "6792992" "Male")
data2=("Santi" "Texas" "BGG" "6792992" "Male")
data3=("Tiago" "Rio" "GHA" "6792992" "Female")

datacol=("data1" "data2" "data3")

for arrayName in "${datacol[@]}"; do
  declare -n array="$arrayName"
  echo "The second element of the array '$arrayName' is: ${array[1]}"
done

其产生:

$ foo.sh
The second element of the array 'data1' is: Barcelona
The second element of the array 'data2' is: Texas
The second element of the array 'data3' is: Rio

它真的很复杂、脆弱,不值得付出努力。请改用真正的脚本语言。

答案2

在 Bash 中你做不到,没有技巧的话。不过,Ksh93 确实具有本机多维数组。

一种常见的技巧是使用关联数组 ( declare -A arr),并使用 , 之类的键1,2,多个索引之间用逗号分隔。尽管迭代单个“行”或“列”并不那么简单。这也是 AWK 实现多维数组的方式,参见例如GNU AWK 手册

以克什为单位:

arr=((a b c) (d e f))       # 3x2
arr[2]=(g h i)              # one more row
arr[0][2]=x                 # change a value
typeset -p arr
echo ---
for i in ${!arr[@]}; do     # ${!arr[@]} gives the indexes
   for j in ${!arr[i][@]}; do
      echo -n "${arr[i][j]} ";
   done;
   echo;
done

印刷

typeset -a arr=((a b x) (d e f) (g h i) )
---
a b x 
d e f 
g h i 

但实际上,这是您可能应该考虑改用 Python(或 Perl,或...)的情况之一,除非您的用例非常特殊。 shell 语言使启动外部程序变得容易,但处理数据结构却困难得多。

答案3

我发现“滥用”数组可以达到你想要的效果:

#!/bin/bash

AllServers=(
    "vmkm13, 172.16.39.71"
    "vmkm14, 172.16.39.72"
    "vmkm15, 172.16.39.84"
    "vmkw51, 172.16.39.73"
    "vmkw52, 172.16.39.74"
    "vmkw53, 172.16.39.75"
    "vmkw54, 172.16.39.76"
    "vmkw55, 172.16.39.77"
    "vmkw56, 172.16.39.78"
    "vmkw57, 172.16.39.79"
    "vmkw58, 172.16.39.80"
    "vmkw59, 172.16.39.81"
    "vmkw60, 172.16.39.82"
    "vmkw61, 172.16.39.83"
    "vmkw62, 172.16.39.85"
    "vmkw63, 172.16.39.86"
    "vmkw64, 172.16.39.87"

)

for Servers in "${AllServers[@]}"; do
    Servername=$(echo "$Servers" | awk -F',' '{ print $1 }')
    ServerIP=$(echo "$Servers" | awk -F',' '{ print $2 }')

done

这绝不是正确的。但是将数据括在双引号中,然后用逗号分隔条目,可以让您使用 AWK 之类的工具将列条目提取到变量中。我确实说过这是一种非常hacky的方法。但它有效。

答案4

declare -p这很hacky,但是您可以使用(typeset -p也可以)序列化数组。使用该策略,您可以在 bash 中创建一系列序列化数组,然后创建eval它们。请注意,如果我们关心空字符串作为值,则必须使用引号:

# multidimensional array serialized with `declare -p`
# red, yellow, green things
declare -a color_table=(
  "$(inner_row=(stop caution go);          declare -p inner_row)"
  "$(inner_row=(rose tulip clover);        declare -p inner_row)"
  "$(inner_row=(strawberry banana grape);  declare -p inner_row)"
)

以下是如何使用该多维数组:

# using eval, we deserialize the inner_row variable as we loop
echo "=== table ==="
printf '%s\n' "${color_table[@]}"
echo "=== rows ==="
for row in "${color_table[@]}"; do
  eval $row
  echo "red thing: ${inner_row[0]}"
  echo "yellow thing: ${inner_row[1]}"
  echo "green thing: ${inner_row[2]}"
done

输出是:

=== table ===
declare -a inner_row=([0]="stop" [1]="caution" [2]="go")
declare -a inner_row=([0]="rose" [1]="tulip" [2]="clover")
declare -a inner_row=([0]="strawberry" [1]="banana" [2]="grape")
=== rows ===
red thing: stop
yellow thing: caution
green thing: go
red thing: rose
yellow thing: tulip
green thing: clover
red thing: strawberry
yellow thing: banana
green thing: grape

对于 Zsh 用户,请记住数组从 1 开始,因此此脚本将起作用,但在此示例中不使用 0-2 进行索引,而是使用 1-3。

相关内容