shell ksh:将函数输出赋给数组

fcipmucu  于 2022-12-27  发布在  Shell
关注(0)|答案(2)|浏览(120)

为什么这不起作用???

#!/bin/ksh

# array testfunc()
function testfunc {
    typeset -A env
    env=( one="motherload" )
            print -r $env
    return 0
}

testfunc # returns: ( one=motherload )
typeset -A testvar # segfaults on linux, memfaults on solaris 
testvar=$(testfunc) # segfaults on linux, memfaults on solaris
print ${testvar.one}

注意:我将上面的脚本从print $testvar更新为print ${testvar.one},以更精确地显示我试图完成的任务。
我敢肯定,这已经问过之前,但我不知道该搜索什么和一切我一直试图使用的关键字是不会给我带来任何答案,涉及到我的问题。
ksh版本:
linux: version sh (AT&T Research) 1993-12-28 s+
solaris: version sh (AT&T Research) 93s+ 2008-01-31
更新:
所以另一个问题是,这个函数在ksh 93t+中运行时不会出错,但是它没有正确地赋值数组,我应该从函数中赋值数组吗?我也试着像这样赋值数组:

typeset -A testvar=$(testfunc)
print ${testvar.one}

但这也不能正常工作。
编辑
这是怎么回事?

typeset -A env=( one="motherload" two="vain" )
print ${env.one}
print ${env.two}

我以为这就是你定义关联数组的方式,也许我看到的是旧的,但谁知道呢......似乎很奇怪,因为这会打印出"motherload"和"vain"

qoefvg9y

qoefvg9y1#

您的脚本对我来说在Linux上使用ksh 93t+运行良好。
由于这是同一个脚本,并且在两个不同的环境中出现了类似的错误,我怀疑文件中存在杂散字符。请尝试以下方法之一,以显示可能存在的杂散字符:

hd filename
cat -v filename
hexdump -C filename

如果这只是DOS行结束的问题,那么这将修复:

dos2unix filename
    • 编辑:**

下面是在ksh中创建和填充关联数组的一种方法:

$ typeset -A testvar
$ testvar=([one]="motherlode" [two]="vein" [waste]="tailings")
$ echo ${testvar[two]}
vein
$ testvar[ore]="gold"
$ echo ${!testvar[@]}    # print the indices of the array
one two waste ore
$ typeset -p testvar     # show the current definition of the array
typeset -A testvar=([one]="motherlode" [two]="vein" [waste]="tailings" [ore]="gold")

正如您所看到的,ksh对数组使用方括号下标,点线符号用于访问compound variable的成员。
我不相信ksh函数可以返回数组,但是,你可以使用函数中的print技术(但是在索引名周围加上方括号),并使用eval来进行赋值。

$ typeset -A testvar 
$ eval "testvar=($(testfunc))"

或追加到现有数组:

$ eval "testvar+=($(testfunc))"

除非函数内部使用了关联数组,否则不必使用它们来构建输出。
但是,如果您这样做,则可以从typeset -p的结果中进行解析:

$ result=$(typeset -p env)
$ result=${result#*\(}
$ result=${result%\)*}
$ print result

或循环访问数组:

$ for index in ${!env[@]}; do print -n "[$index]=${env[$index]} "; done; print

您可能需要查阅有关规程函数和类型变量的文档

ckocjqey

ckocjqey2#

这里有一个替代方法,可以用name reference从函数中获取返回值,返回值将存储在一个定义为函数第一个位置参数的变量中(不预先声明变量也可以,但变量将是全局变量):

#################################
# Example using compound variable
#################################
function returnCompound {
    typeset -n returnVal="$1"
    returnVal=( one="motherloadCompound" )
    return 0
}

# Declaring the variable to keep it in this scope
# Useful for calling nested functions whitout messing 
# with the global scope
typeset myNewCompoundVar
returnCompound myNewCompoundVar
echo "Compound: ${myNewCompoundVar.one}"

##################################
# Example using asssociative array
##################################
function returnMap {
    typeset -n myNewMapVar="$1"
    myNewMapVar=( [one]="motherloadMap" )

    typeset nestedCompoundVar
    returnCompound nestedCompoundVar
    echo "Compound (Nested) from inside: ${nestedCompoundVar.one}"

    return 0
}

# Declaring the variable to keep it in this scope
# Useful for calling nested functions whitout messing 
# with the global scope 
typeset myNewMapVar
returnMap myNewMapVar
echo "Associative array: ${myNewMapVar[one]}"
echo "Compound (Nested) from outside: ${nestedCompoundVar.one}"
    • 输出:**
Compound: motherloadCompound
Compound (Nested) from inside: motherloadCompound
Associative array: motherloadMap
Compound (Nested) from outside:
    • 重要附注:**
  • 函数声明必须使用function关键字,否则局部作用域变量的概念将不会被考虑。在这种情况下,引用变量和全局变量的名称可能会冲突,如果他们碰巧是相同的,导致排版:无效的自引用错误。可以通过更改"returnMap"函数的声明来测试此错误。
  • 如果在函数调用之前没有声明返回变量,则将全局创建分配了返回值的变量,而不限于调用范围。

相关问题