How do I convert command-line arguments into a bash script array?
I want to take this:
./something.sh arg1 arg2 arg3
and convert it to
myArray=( arg1 arg2 arg3 )
so that I can use myArray for further use in the script.
This previous SO post comes close, but doesn't go into how to create an array: How do I parse command line arguments in Bash?
I need to convert the arguments into a regular bash script array; I realize I could use other languages (Python, for instance) but need to do this in bash. I guess I'm looking for an "append" function or something similar?
UPDATE: I also wanted to ask how to check for zero arguments and assign a default array value, and thanks to the answer below, was able to get this working:
if [ "$#" -eq 0 ]; then
myArray=( defaultarg1 defaultarg2 )
else
myArray=( "$@" )
fi
Actually your command line arguments are practically like an array already. At least, you can treat the $@
variable much like an array. That said, you can convert it into an actual array like this:
myArray=( "$@" )
If you just want to type some arguments and feed them into the $@
value, use set
:
$ set -- apple banana "kiwi fruit"
$ echo "$#"
3
$ echo "$@"
apple banana kiwi fruit
Understanding how to use the argument structure is particularly useful in POSIX sh, which has nothing else like an array.
Maybe this can help:
myArray=("$@")
also you can iterate over arguments by omitting 'in':
for arg; do
echo "$arg"
done
will be equivalent
for arg in "${myArray[@]}"; do
echo "$arg"
done
arg
field - is it a predefined variable? ${var}
is expanded to the content of var
. ${var[n]}
is expanded to the content of element n
of array var
. Is ${var[@]}
then expanding the entire array, i.e. ${var[0]} ${var[1]} ... ${var[n]}
(with n
being the last element's index)?
Actually the list of parameters could be accessed with $1 $2 ...
etc.
Which is exactly equivalent to:
${!i}
So, the list of parameters could be changed with set,
and ${!i}
is the correct way to access them:
$ set -- aa bb cc dd 55 ff gg hh ii jjj kkk lll
$ for ((i=0;i<=$#;i++)); do echo "$#" "$i" "${!i}"; done
12 1 aa
12 2 bb
12 3 cc
12 4 dd
12 5 55
12 6 ff
12 7 gg
12 8 hh
12 9 ii
12 10 jjj
12 11 kkk
12 12 lll
For your specific case, this could be used (without the need for arrays), to set the list of arguments when none was given:
if [ "$#" -eq 0 ]; then
set -- defaultarg1 defaultarg2
fi
which translates to this even simpler expression:
[ "$#" == "0" ] && set -- defaultarg1 defaultarg2
echo "$#" "$i+1" "${!i}";
to get the output exactly as shown?
Here is another usage :
#!/bin/bash
array=( "$@" )
arraylength=${#array[@]}
for (( i=0; i<${arraylength}; i++ ));
do
echo "${array[$i]}"
done
Easier Yet, you can operate directly on $@
;)
Here is how to do pass a a list of args directly from the prompt:
function echoarg { for stuff in "$@" ; do echo $stuff ; done ; }
echoarg Hey Ho Lets Go
Hey
Ho
Lets
Go
for stuff in "$@" ; do ...
is same as for stuff ; do ...
:)
The importance of the double quotes is worth emphasizing. Suppose an argument contains whitespace.
Code:
#!/bin/bash
printf 'arguments:%s\n' "$@"
declare -a arrayGOOD=( "$@" )
declare -a arrayBAAD=( $@ )
printf '\n%s:\n' arrayGOOD
declare -p arrayGOOD
arrayGOODlength=${#arrayGOOD[@]}
for (( i=1; i<${arrayGOODlength}+1; i++ ));
do
echo "${arrayGOOD[$i-1]}"
done
printf '\n%s:\n' arrayBAAD
declare -p arrayBAAD
arrayBAADlength=${#arrayBAAD[@]}
for (( i=1; i<${arrayBAADlength}+1; i++ ));
do
echo "${arrayBAAD[$i-1]}"
done
Output:
> ./bash-array-practice.sh 'The dog ate the "flea" -- and ' the mouse.
arguments:The dog ate the "flea" -- and
arguments:the
arguments:mouse.
arrayGOOD:
declare -a arrayGOOD='([0]="The dog ate the \"flea\" -- and " [1]="the" [2]="mouse.")'
The dog ate the "flea" -- and
the
mouse.
arrayBAAD:
declare -a arrayBAAD='([0]="The" [1]="dog" [2]="ate" [3]="the" [4]="\"flea\"" [5]="--" [6]="and" [7]="the" [8]="mouse.")'
The
dog
ate
the
"flea"
--
and
the
mouse.
>
Side-by-side view of how the array and $@ are practically the same.
Code:
#!/bin/bash
echo "Dollar-1 : $1"
echo "Dollar-2 : $2"
echo "Dollar-3 : $3"
echo "Dollar-AT: $@"
echo ""
myArray=( "$@" )
echo "A Val 0: ${myArray[0]}"
echo "A Val 1: ${myArray[1]}"
echo "A Val 2: ${myArray[2]}"
echo "A All Values: ${myArray[@]}"
Input:
./bash-array-practice.sh 1 2 3 4
Output:
Dollar-1 : 1
Dollar-2 : 2
Dollar-3 : 3
Dollar-AT: 1 2 3 4
A Val 0: 1
A Val 1: 2
A Val 2: 3
A All Values: 1 2 3 4
Success story sharing
set
allows you to set positional parameters for the scope. It also lets you set shell options. You can doset foo
, which will mean$1
expands to "foo", but if your parameters start with a dashset
will assume you mean to set a shell option. The double-dash ensures that all the following parameters are interpreted as positional parameters to be set.echo $@
will print all the arguments, butecho $myArray
will only print the first element. To see them all, useecho ${myArray[@]}
."${myArray[@]}"
. If you want to loop through the array, you need the quotes to avoid splitting its individual elements on IFS