8

In zsh, how do I pass anonymous arrays into functions? e.g. looking for something like:

foo() {
  echo ${1[2]} '\n';
}

a=(abc def ghi)
foo $a

--> def

Or ideally:

foo (abc def ghi)
Jason Plank
  • 2,336
  • 5
  • 31
  • 40
Aaron Fi
  • 10,116
  • 13
  • 66
  • 91
  • Note that nothing above actually works. – Aaron Fi Jan 14 '09 at 05:28
  • Probably best to re-title and re-word this question, since your own answer is not for the question stated. To retain the value of the other answers, it might be best to just re-post the actual question and then accept one of the correct answers. – ocodo Jul 30 '22 at 09:22

5 Answers5

11

You can pass the name of the array to the function and then the function can read the array by interpreting the name as a variable name. It is a technique that is also useful for things like associative arrays in bash. ZSH makes it very easy to do, as the (P) operator will interpret the variable in the desired way.

An example will make this clear. If you define this function:

function i_want_array () {
    local array_name=$1

    echo "first array element is: " ${(P)${array_name}[1]}
}

Then the following code will execute it:

% a=(one two three)
% i_want_array "a"
first array element is:  one

And just to clarify, this works by operating on the real array, so any whitespace is handled correctly:

% a=("one two" three)
% i_want_array "a"
first array element is:  one two
Matthew Franglen
  • 4,441
  • 22
  • 32
  • This magic works:) Though one important notion: the local variable's name can't be the same as the outer variable that stores the array values. I. e. in the example above the outer variable is `a` and the local variable is `array_name`. If you have those 2 variables of the same name, the solution won't work. – vladZams Aug 08 '22 at 22:30
5

You can't. Functions take positional parameters like any other command.

Note also that your workaround doesn't allow any of the "array" elements to contain whitespace.

The cleanest thing I can think of is to require that the caller create a local array, then read it from the function:

$ foo() {
   for element in $FOO_ARRAY
   do
       echo "[$element]"
   done
}
$ local FOO_ARRAY; FOO_ARRAY=(foo bar baz quux)
$ foo
[foo]
[bar]
[baz]
[quux]

I know bash does similar acrobatics for its completion system, and I think zsh might, too. It's not too unusual.

Eevee
  • 47,412
  • 11
  • 95
  • 127
  • Thanks. This solved my problem which was how to create an array in a function and unset it after use in the simplest possible way. Answer: `local`. – Denis Howe Sep 06 '22 at 17:49
1

If you only need one array parameter: as tail args.

foo() {
  : if you have any leading non-array args, grab those first:
  local arg1="$1"
  shift
  local arg2="$1"
  shift
  : now $@ is your array arg
  echo $@[2] '\n';
}

a=(abc def ghi)
foo "arg 1" arg2 $a

--> def
ecmanaut
  • 5,030
  • 2
  • 44
  • 66
0

Not solved with an anonymous array ... But i tried this thing in !! BASH !!...

function join {
  local tmp=($1)

  for (( i=0 ; i<${#tmp[@]}-1 ; i++ )) ; do
    echo -n ${tmp[$i]}$2
  done

  echo ${tmp[$i]}
}

test="abc def ghi"

join "$test" "|"
mipe34
  • 5,596
  • 3
  • 26
  • 38
-3

Figured out a workaround:

foo() {
  local a=$1
  local b=$2

  echo ${(j:---:)${=b}}

  foreach d in ${${=b}}
  do
      echo $d
  done
}

Where parameter2 is a string of white-separated text, e.g. 'a badkljf odod'

Aaron Fi
  • 10,116
  • 13
  • 66
  • 91
  • 3
    This may be a workaround for your particular unexpressed requirements, but it has pretty much nothing to do with the question. This is an anwer to the question, "How do I split a parameter?" – peth Nov 08 '12 at 01:09