这个问题的目的是发布一个非明显解决方案的规范答案 - 复制数组数组(数组数组需要 GNU awk)。
给定一个数组数组,例如关于遍历数组部分的 gawk 手册中所示:
BEGIN {
a[1] = 1
a[2][1] = 21
a[2][2] = 22
a[3] = 3
a[4][1][1] = 411
a[4][2] = 42
walk_array(a, "a")
}
function walk_array(arr, name, i)
{
for (i in arr) {
if (isarray(arr[i]))
walk_array(arr[i], (name "[" i "]"))
else
printf("%s[%s] = %s\n", name, i, arr[i])
}
}
Run Code Online (Sandbox Code Playgroud)
您将如何编写一个copy_array可以处理数组数组以将现有数组复制到新数组的函数,walk_array()以便对新复制数组的后续调用将为新数组输出与原始数组相同的值,即这样:
BEGIN {
a[1] = 1
a[2][1] = 21
a[2][2] = 22
a[3] = 3
a[4][1][1] = 411
a[4][2] = 42
walk_array(a, "a")
copy_array(a, b)
print "----------"
walk_array(b, "b")
}
Run Code Online (Sandbox Code Playgroud)
会输出:
a[1] = 1
a[2][1] = 21
a[2][2] = 22
a[3] = 3
a[4][1][1] = 411
a[4][2] = 42
----------
b[1] = 1
b[2][1] = 21
b[2][2] = 22
b[3] = 3
b[4][1][1] = 411
b[4][2] = 42
Run Code Online (Sandbox Code Playgroud)
$ cat tst.awk
BEGIN {
a[1] = 1
a[2][1] = 21
a[2][2] = 22
a[3] = 3
a[4][1][1] = 411
a[4][2] = 42
walk_array(a, "a")
copy_array(a, b)
print "----------"
walk_array(b, "b")
}
function copy_array(orig, copy, i)
{
delete copy # Empty "copy" for first call and delete the temp
# array added by copy[i][1] below for subsequent.
for (i in orig) {
if (isarray(orig[i])) {
copy[i][1] # Force copy[i] to also be an array by creating a temp
copy_array(orig[i], copy[i])
}
else {
copy[i] = orig[i]
}
}
}
function walk_array(arr, name, i)
{
for (i in arr) {
if (isarray(arr[i]))
walk_array(arr[i], (name "[" i "]"))
else
printf("%s[%s] = %s\n", name, i, arr[i])
}
}
Run Code Online (Sandbox Code Playgroud)
.
$ awk -f tst.awk
a[1] = 1
a[2][1] = 21
a[2][2] = 22
a[3] = 3
a[4][1][1] = 411
a[4][2] = 42
----------
b[1] = 1
b[2][1] = 21
b[2][2] = 22
b[3] = 3
b[4][1][1] = 411
b[4][2] = 42
Run Code Online (Sandbox Code Playgroud)
copy[i][1]在内部调用之前创建临时数组的使用,copy_array()然后在进入时删除该数组copy_array()是为了避免后续代码假设存在的内容copy[i]是标量 - 这与您必须在之前创建临时数组的方式相同使用split()(在内部首先删除您作为参数传递的 arry)来填充子数组,因为默认情况下假定数组元素的内容是标量,以便与为不支持数组数组的 awks 编写的代码向后兼容(例如POSIX awks):
$ printf 'a b\nc d\n' |
awk '{split($0,arr[NR])} END{for (i in arr) for (j in arr[i]) print i,j,arr[i][j]}'
awk: cmd. line:1: (FILENAME=- FNR=1) fatal: split: second argument is not an array
$ printf 'a b\nc d\n' |
awk '{arr[NR][1]; split($0,arr[NR])} END{for (i in arr) for (j in arr[i]) print i,j,arr[i][j]}'
1 1 a
1 2 b
2 1 c
2 2 d
Run Code Online (Sandbox Code Playgroud)