Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass an array via command-line to be handled with getopts()

Tags:

bash

I try to pass some parameters to my .bash file.

terminal:

arr=("E1" "E2" "E3")
param1=("foo")
param2=("bar")

now I want to call my execute.bash file.

execute.bash -a ${arr[@]} -p $param1 -c param2

this is my file:

execute.bash:
while getopts ":a:p:c:" opt; do
    case $opt in
        a) ARRAY=${OPTARG};;
        p) PARAM1=${OPTARG};;
        c) PARAM2=${OPTARG};;
        \?) exit "Invalid option -$OPTARG";;
    esac
done

for a in "${ARRAY[@]}"; do
    echo "$a"
done

echo "$PARAM1"
echo "$PARAM2"

But my file only prints:

E1
foo
bar

Whats the problem with my script?

like image 852
Rod Kimble Avatar asked Sep 15 '25 19:09

Rod Kimble


1 Answers

You have a problem with passing the array as one of the parameter for the -a flag. Arrays in bash get expanded in command line before the actual script is invoked. The "${array[@]}" expansions outputs words separated by white-space

So your script is passed as

-a "E1" "E2" "E3" -p foo -c bar

So with the getopts() call to the argument OPTARG for -a won't be populated with not more than the first value, i.e. only E1. One would way to achieve this is to use the array expansion of type "${array[*]}" which concatenates the string with the default IFS (white-space), so that -a now sees one string with the words of the array concatenated, i.e. as if passed as

-a "E1 E2 E3" -p foo -c bar

I've emphasized the quote to show arg for -a will be received in getopts()

#!/usr/bin/env bash

while getopts ":a:p:c:" opt; do
    case $opt in
        a) ARRAY="${OPTARG}";;
        p) PARAM1="${OPTARG}";;
        c) PARAM2="${OPTARG}";;
        \?) exit "Invalid option -$OPTARG";;
    esac
done

# From the received string ARRAY we are basically re-constructing another
# array splitting on the default IFS character which can be iterated over
# as in your input example

read -r -a splitArray <<<"$ARRAY"

for a in "${splitArray[@]}"; do
    echo "$a"
done

echo "$PARAM1"
echo "$PARAM2"

and now call the script with args as. Note that you are using param1 and param2 are variables but your definition seems to show it as an array. Your initialization should just look like

arr=("E1" "E2" "E3")
param1="foo"
param2="bar"

and invoked as

-a "${arr[*]}" -p "$param1" -c "$param2"

A word of caution would be to ensure that the words in the array arr don't already contain words that contain spaces. Reading them back as above in that case would have a problem of having those words split because the nature of IFS handling in bash. In that case though use a different de-limiter say |, # while passing the array expansion.

like image 154
Inian Avatar answered Sep 18 '25 10:09

Inian