3

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"

1

2 Answers 2

2

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

Sign up to request clarification or add additional context in comments.

2 Comments

Okay so it works for me also on ksh 93t+... looks like this was an issue in previous <93s+ versions...
actually it just doesn't error, it does not provide the results I was looking for.
0

Here is an alternative to getting any return value from a function using name reference. The value returned will be stored in a variable defined as the first positional argument of the function (not declaring the variable beforehand will work but the variable will be global):

#################################
# 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}"

Output:

Compound: motherloadCompound
Compound (Nested) from inside: motherloadCompound
Associative array: motherloadMap
Compound (Nested) from outside: 

Important side notes:

  • Function declarations must be done using the function keyword or else the concept of local scope variable won't be taken under account. In which case the name of your reference variable and global variable might clash if they happen to be the same, resulting in a typeset: invalid self reference error. This can be tested by changing the declaration of the 'returnMap' function.
  • If you do not declare the return variable before the function call, the variable to which is assigned the return value will be created globally and not limited to the calling scope.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.