【发布时间】:2018-07-26 09:08:16
【问题描述】:
我有一个 shell 脚本,它调用一个函数,该函数根据全局变量的值表现出不同的行为,其输出是我想要存储在数组中的值列表。
我遇到了一个问题,因为当我尝试使用明显语法的任何变体来捕获函数的输出时:
mapfile -i the_array < <( the_function )
在the_function 中设置的全局变量会在the_function 返回后恢复为之前的值。我知道这是捕获具有副作用的函数的输出的已知“功能”,我可以解决它,如下所示,但我想知道:
- bash 的基本原理是什么使这种变通方法成为必要?
- 这真的是解决问题的最佳方法吗?
为了简化问题,考虑这种情况,我希望函数在第一次调用时打印 5 个数字,而在下次调用时不打印任何内容(这是不产生预期输出的明显语法):
$ cat tst1
#!/usr/bin/env bash
the_function() {
printf '\nENTER: %s(), the_variable=%d\n' "${FUNCNAME[0]}" "$the_variable" >&2
if (( the_variable == 0 )); then
seq 5
the_variable=1
fi
printf 'EXIT: %s(), the_variable=%d\n' "${FUNCNAME[0]}" "$the_variable" >&2
}
the_variable=0
mapfile -t arr < <( the_function )
declare -p arr
mapfile -t arr < <( the_function )
declare -p arr
$ ./tst1
ENTER: the_function(), the_variable=0
EXIT: the_function(), the_variable=1
declare -a arr=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5")
ENTER: the_function(), the_variable=0
EXIT: the_function(), the_variable=1
declare -a arr=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5")
由于上述原因,这不起作用,我可以通过编写代码来解决它(这个确实产生预期的输出):
$ cat tst2
#!/usr/bin/env bash
the_function() {
local arr_ref=$1
printf '\nENTER: %s(), the_variable=%d\n' "${FUNCNAME[0]}" "$the_variable" >&2
if (( the_variable == 0 )); then
mapfile -t "$arr_ref" < <( seq 5 )
the_variable=1
else
mapfile -t "$arr_ref" < /dev/null
fi
printf 'EXIT: %s(), the_variable=%d\n' "${FUNCNAME[0]}" "$the_variable" >&2
}
the_variable=0
the_function arr
declare -p arr
the_function arr
declare -p arr
$ ./tst2
ENTER: the_function(), the_variable=0
EXIT: the_function(), the_variable=1
declare -a arr=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5")
ENTER: the_function(), the_variable=1
EXIT: the_function(), the_variable=1
declare -a arr=()
但是,虽然这行得通,但它显然是可怕的代码,因为它要求较低级别的原语比必要的更复杂,并且与用于存储其输出的数据结构紧密耦合(因此,如果出现我们只想要5 个数字去标准输出,例如)。
那么 - 为什么我需要这样做,有没有更好的方法?
【问题讨论】:
标签: arrays bash pass-by-reference side-effects