Search code examples
linuxshellscriptingsolarisksh

ksh: assigning function output to an array


Why doesn't this work???

#!/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}

note: I updated the above script to print ${testvar.one} from print $testvar to show more precisely what I am trying to accomplish.

I am sure this has been asked before, but I am not sure what to search on and everything I have been trying to use for keywords is not bringing me any answers that relate to my problem.

ksh version:

linux: version sh (AT&T Research) 1993-12-28 s+

solaris: version sh (AT&T Research) 93s+ 2008-01-31

Update:

So another question is, this will run in ksh 93t+ without giving an error, but, it doesn't assign the array properly. I would I go about assigning an array from a function? I tried assigning the array like this also:

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

But that also didn't work properly.

EDIT

So what is happening here?

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

I thought this was how you defined associative arrays, maybe what I was looking at was old but who knows.... seems odd behaviour since this prints out "motherload" and "vain"


Solution

  • Your script works fine for me on Linux with ksh 93t+.

    Since it's the same script and you're getting similar errors in two different environments, I would suspect stray characters in the file. Try one of these to show any stray characters that might be present:

    hd filename
    cat -v filename
    hexdump -C filename
    

    If it's simply a matter of DOS line endings, then this will fix that:

    dos2unix filename
    

    Edit:

    Here's one way to create and populate an associative array in 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")
    

    As you can see, ksh uses bracketed subscripts for arrays. Dotted notation is used for accessing members of a compound variable.

    I don't believe ksh functions can return arrays. However, you can use the print technique you have in your function (but add square brackets around the index name) and use eval to do the assignment.

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

    or to append to an existing array:

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

    Unless your function is using associative arrays internally, you don't necessarily need to use them to build your output.

    However, if you do, you can parse from the result of typeset -p:

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

    or iterate through the array:

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

    You may want to consult the documentation concerning discipline functions and type variables