230

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
codeforester
  • 39,467
  • 16
  • 112
  • 140
Suman
  • 9,221
  • 5
  • 49
  • 62

7 Answers7

273

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
$ for arg in "${@}"; do echo -n ", $arg"; done
, apple, banana, kiwi, fruit

Understanding how to use the argument structure is particularly useful in POSIX sh, which has nothing else like an array.

dank8
  • 361
  • 4
  • 20
kojiro
  • 74,557
  • 19
  • 143
  • 201
  • 3
    Thanks! Works great! Was just about to ask how to check for zero arguments and assign a default array value, and the $# works perfectly for that! – Suman Oct 03 '12 at 15:36
  • 1
    `set` allows you to set positional parameters for the scope. It also lets you set shell options. You can do `set foo`, which will mean `$1` expands to "foo", but if your parameters start with a dash `set` 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. – kojiro Apr 16 '14 at 13:18
  • 18
    One gotcha: `echo $@` will print all the arguments, but `echo $myArray` will only print the first element. To see them all, use `echo ${myArray[@]}`. – z0r Feb 19 '15 at 22:59
  • 7
    @z0r If you don't put double quotes around those expansions then bash will re-wordsplit them, and possibly lose meaning. – kojiro Feb 20 '15 at 02:11
  • 1
    Right, the general way to "splat" an array and use each element is `"${myArray[@]}"`. If you want to loop through the array, you need the quotes to avoid splitting its individual elements on IFS – BallpointBen Aug 13 '18 at 19:15
  • That is very handy to know. I was struggling to find how to `echo` the index number of each element passed as an argument. You just pass the arguments **into** an array as you point out and then you do it. Easy. Very handy, and a solution I have been searching for ! – Kes Jul 02 '21 at 12:54
  • I did not know about `set` either. That is very handy for testing on the command line. Thanks. – Kes Jul 02 '21 at 13:00
82

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 "${@}"; do
   echo "$arg"
done
Mossab
  • 818
  • 8
  • 13
Nahuel Fouilleul
  • 18,726
  • 2
  • 31
  • 36
  • 5
    Newbie questions: How does bash know what to put into the `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)? – Christian Sep 21 '16 at 18:27
  • 6
    [for] without [in] will loop over arguments array $@ ($1,$2, etc.). Which can be set also with [set] command, for example set -- arg1 arg2 – Nahuel Fouilleul Sep 28 '16 at 09:14
22

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
Yaron
  • 10,166
  • 9
  • 45
  • 65
  • 1
    Shouldn't the echo example be: `echo "$#" "$i+1" "${!i}";` to get the output exactly as shown? – Zael Jun 08 '18 at 12:18
  • @Zael for antiquity. you are correct there is a fault in the for logic. `$0` prints the script name change initalise at 1 `for((i=1;i<=$#;i++));` – dank8 May 22 '23 at 07:50
13

Here is another usage :

#!/bin/bash
array=( "$@" )
arraylength=${#array[@]}
for (( i=0; i<${arraylength}; i++ ));
do
   echo "${array[$i]}"
done
kittydoor
  • 101
  • 12
tuğrul altun
  • 131
  • 1
  • 4
5

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
Yaron
  • 10,166
  • 9
  • 45
  • 65
runlevel0
  • 2,715
  • 2
  • 24
  • 31
3

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.
> 
Jacob Wegelin
  • 1,304
  • 11
  • 16
2

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
Kirin
  • 29
  • 1