42

It is surprising me that I do not find the answer after 1 hour search for this. I would like to pass an array to my script like this:

test.sh argument1 array argument2

I DO NOT want to put this in another bash script like following:

array=(a b c)
for i in "${array[@]}"
do
  test.sh argument1 $i argument2
done
codeforester
  • 34,080
  • 14
  • 96
  • 122
zhihong
  • 1,658
  • 2
  • 23
  • 32

5 Answers5

37

Bash arrays are not "first class values" -- you can't pass them around like one "thing".

Assuming test.sh is a bash script, I would do

#!/bin/bash
arg1=$1; shift
array=( "$@" )
last_idx=$(( ${#array[@]} - 1 ))
arg2=${array[$last_idx]}
unset array[$last_idx]

echo "arg1=$arg1"
echo "arg2=$arg2"
echo "array contains:"
printf "%s\n" "${array[@]}"

And invoke it like

test.sh argument1 "${array[@]}" argument2
glenn jackman
  • 223,850
  • 36
  • 205
  • 328
  • Great answer. I know this doesn't conform to OP's requirement of `test.sh argument1 array argument2` but if the invocation was changed to `test.sh argument1 argument2 array` (the array being the last), it'd be less work. – doubleDown Jun 21 '13 at 10:58
  • 4
    Good answer. But technically it is not passing array to a script. What if OP needs to pass 2 array variables to this script like `test.sh argument1 array1 array2` – anubhava Jun 21 '13 at 11:11
  • 1
    Note that you need to declare the array before calling the script. For the OP, this would mean `$ array=(a b c)` and then `test.sh argument1 "${array[@]}" argument2` . It might only be me who had to think about that a bit, but I'm commenting in the hope that it will help someone. – bballdave025 Apr 06 '19 at 22:14
18

Have your script arrArg.sh like this:

#!/bin/bash

arg1="$1"
arg2=("${!2}")
arg3="$3"
arg4=("${!4}")

echo "arg1=$arg1"
echo "arg2 array=${arg2[@]}"
echo "arg2 #elem=${#arg2[@]}"
echo "arg3=$arg3"
echo "arg4 array=${arg4[@]}"
echo "arg4 #elem=${#arg4[@]}"

Now setup your arrays like this in a shell:

arr=(ab 'x y' 123)
arr2=(a1 'a a' bb cc 'it is one')

And pass arguments like this:

. ./arrArg.sh "foo" "arr[@]" "bar" "arr2[@]"

Above script will print:

arg1=foo
arg2 array=ab x y 123
arg2 #elem=3
arg3=bar
arg4 array=a1 a a bb cc it is one
arg4 #elem=5

Note: It might appear weird that I am executing script using . ./script syntax. Note that this is for executing commands of the script in the current shell environment.

Q. Why current shell environment and why not a sub shell?
A. Because bash doesn't export array variables to child processes as documented here by bash author himself

anubhava
  • 713,503
  • 59
  • 514
  • 593
1

If values have spaces (and as a general rule) I vote for glenn jackman's answer, but I'd simplify it by passing the array as the last argument. After all, it seems that you can't have multiple array arguments, unless you do some complicated logic to detect their boundaries.

So I'd do:

ARRAY=("the first" "the second" "the third")
test.sh argument1 argument2 "${ARRAY[@]}"

which is the same as:

test.sh argument1 argument2 "the first" "the second" "the third"

And in test.sh do:

ARG1="$1"; shift
ARG2="$1"; shift
ARRAY=("$@")

If values have no spaces (i.e. they are urls, identifiers, numbers, etc) here's a simpler alternative. This way you can actually have multiple array arguments and it's easy to mix them with normal arguments:

ARRAY1=(one two three)
ARRAY2=(four five)
test.sh argument1 "${ARRAY1[*]}" argument3 "${ARRAY2[*]}" 

which is the same as:

test.sh argument1 "one two three" argument3 "four five"

And in test.sh you do:

ARG1="$1"
ARRAY1=($2) # Note we don't use quotes now
ARG3="$3"
ARRAY2=($4)

I hope this helps. I wrote this to help (you and me) understand how arrays work, and how * an @ work with arrays.

Ferran Maylinch
  • 10,227
  • 14
  • 75
  • 93
0

You can write your array to a file, then source the file in your script. e.g.:

array.sh

array=(a b c)

test.sh

source $2
...

Run the test.sh script:

./test.sh argument1 array.sh argument3
Dd H
  • 191
  • 1
  • 2
  • 9
-4

If this is your command:

test.sh argument1 ${array[*]} argument2

You can read the array into test.sh like this:

arg1=$1
arg2=${2[*]}
arg3=$3

It will complain at you ("bad substitution"), but will work.